From 2f9a0bbe756cc0ed3055ad0b076ee0a48723d777 Mon Sep 17 00:00:00 2001 From: "Mike Dalessio (aider)" Date: Wed, 14 May 2025 11:46:47 -0400 Subject: [PATCH] Introduce a recurring job to delete unused tags ref: https://37s.fizzy.37signals.com/collections/693169850/cards/999009072 --- app/jobs/delete_unused_tags_job.rb | 9 +++++++++ app/models/tag.rb | 1 + config/recurring.yml | 3 +++ test/jobs/delete_unused_tags_job_test.rb | 13 +++++++++++++ test/models/tag_test.rb | 14 ++++++++++++++ 5 files changed, 40 insertions(+) create mode 100644 app/jobs/delete_unused_tags_job.rb create mode 100644 test/jobs/delete_unused_tags_job_test.rb diff --git a/app/jobs/delete_unused_tags_job.rb b/app/jobs/delete_unused_tags_job.rb new file mode 100644 index 000000000..a733a0e75 --- /dev/null +++ b/app/jobs/delete_unused_tags_job.rb @@ -0,0 +1,9 @@ +class DeleteUnusedTagsJob < ApplicationJob + def perform + ApplicationRecord.with_each_tenant do |tenant| + Tag.unused.find_each do |tag| + tag.destroy! + end + end + end +end diff --git a/app/models/tag.rb b/app/models/tag.rb index eadaa72f9..ce981f4ab 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -8,6 +8,7 @@ class Tag < ApplicationRecord normalizes :title, with: -> { it.downcase } scope :alphabetically, -> { order("lower(title)") } + scope :unused, -> { left_outer_joins(:taggings).where(taggings: { id: nil }) } def hashtag "#" + title diff --git a/config/recurring.yml b/config/recurring.yml index 9aff145ac..7be0c716a 100644 --- a/config/recurring.yml +++ b/config/recurring.yml @@ -11,3 +11,6 @@ production: sqlite_backups: class: SQLiteBackupsJob schedule: every day at 05:00 + delete_unused_tags: + class: DeleteUnusedTagsJob + schedule: every day at 04:00 diff --git a/test/jobs/delete_unused_tags_job_test.rb b/test/jobs/delete_unused_tags_job_test.rb new file mode 100644 index 000000000..8c6c8b595 --- /dev/null +++ b/test/jobs/delete_unused_tags_job_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class DeleteUnusedTagsJobTest < ActiveJob::TestCase + test "deletes tags that are not used by any cards" do + unused = Tag.create!(title: "unused") + + assert_changes -> { Tag.count }, -1 do + DeleteUnusedTagsJob.perform_now + end + + assert_not Tag.exists?(unused.id), "Unused tag should be deleted" + end +end diff --git a/test/models/tag_test.rb b/test/models/tag_test.rb index f60e6f9ee..61031f533 100644 --- a/test/models/tag_test.rb +++ b/test/models/tag_test.rb @@ -4,4 +4,18 @@ class TagTest < ActiveSupport::TestCase test "downcase title" do assert_equal "a tag", Tag.create!(title: "A TAG").title end + + test ".unused returns tags not associated with any cards" do + unused = Tag.create!(title: "unused") + + unused_tags = Tag.unused + + assert_includes unused_tags, unused + assert_not_includes unused_tags, tags(:web) + assert_not_includes unused_tags, tags(:mobile) + end + + test ".unused returns empty relation if all tags are used" do + assert_empty Tag.unused + end end