From e8db68b16198071f3eb69a0a72840845a48f7aad Mon Sep 17 00:00:00 2001 From: ArtOfCode- Date: Sun, 20 Oct 2024 19:45:26 +0100 Subject: [PATCH 1/3] Silently substitute synonyms for tags --- app/models/post.rb | 6 +++++- app/models/tag.rb | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/models/post.rb b/app/models/post.rb index de81fb53e..256b7ec85 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -203,10 +203,14 @@ def reaction_list # Updates the tags association from the tags_cache. def update_tag_associations tags_cache.each do |tag_name| - tag = Tag.find_or_create_by name: tag_name, tag_set: category.tag_set + tag, name = Tag.find_or_create_synonymized name: tag_name, tag_set: category.tag_set unless tags.include? tag tags << tag end + unless tags_cache.include? name + tags_cache.delete tag_name + tags_cache << name + end end tags.each do |tag| unless tags_cache.include? tag.name diff --git a/app/models/tag.rb b/app/models/tag.rb index 3fc1dff71..a9434fbf4 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -38,6 +38,17 @@ def self.search(term) .distinct end + def self.find_or_create_synonymized(name:, tag_set:) + existing = Tag.find_by(name: name, tag_set: tag_set) + if !existing.nil? + [existing, name] + else + synonyms = TagSynonym.joins(:tag).where(name: name, tags: { tag_set: tag_set }) + synonymized_name = synonyms.exists? ? synonyms.first.tag.name : name + [Tag.find_or_create_by(name: synonymized_name, tag_set: tag_set), synonymized_name] + end + end + def all_children query = File.read(Rails.root.join('db/scripts/tag_children.sql')) query = query.gsub('$ParentId', id.to_s) From 49a4653b01b5fbf91a6ccea56214cf2202d2a6c8 Mon Sep 17 00:00:00 2001 From: ArtOfCode- Date: Sun, 20 Oct 2024 19:49:06 +0100 Subject: [PATCH 2/3] Rubocop --- app/models/tag.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/tag.rb b/app/models/tag.rb index a9434fbf4..b3e4f4ae3 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -40,12 +40,12 @@ def self.search(term) def self.find_or_create_synonymized(name:, tag_set:) existing = Tag.find_by(name: name, tag_set: tag_set) - if !existing.nil? - [existing, name] - else + if existing.nil? synonyms = TagSynonym.joins(:tag).where(name: name, tags: { tag_set: tag_set }) synonymized_name = synonyms.exists? ? synonyms.first.tag.name : name [Tag.find_or_create_by(name: synonymized_name, tag_set: tag_set), synonymized_name] + else + [existing, name] end end From d906e77dc461bcc038bb60d639b6159fdb8e5ae4 Mon Sep 17 00:00:00 2001 From: ArtOfCode- Date: Sun, 20 Oct 2024 20:12:53 +0100 Subject: [PATCH 3/3] Comments --- app/models/post.rb | 16 +++++++++++----- app/models/tag.rb | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 256b7ec85..882f1f399 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -200,16 +200,20 @@ def reaction_list private - # Updates the tags association from the tags_cache. + ## + # Before-validation callback. Update the tags association from the tags_cache. def update_tag_associations tags_cache.each do |tag_name| - tag, name = Tag.find_or_create_synonymized name: tag_name, tag_set: category.tag_set + tag, name_used = Tag.find_or_create_synonymized name: tag_name, tag_set: category.tag_set unless tags.include? tag tags << tag end - unless tags_cache.include? name + + # If the tags_cache doesn't include name_used then tag_name was a synonym - remove the synonym from tags_cache + # and add the primary for it instead. + unless tags_cache.include? name_used tags_cache.delete tag_name - tags_cache << name + tags_cache << name_used end end tags.each do |tag| @@ -219,10 +223,12 @@ def update_tag_associations end end + ## + # Helper method for #check_attribution_notice validator. Produces a text-only attribution notice either based on + # values given or the current state of the post for use in post histories. # @param source [String, Nil] where the post originally came from # @param name [String, Nil] the name of the license # @param url [String, Nil] the url of the license - # # @return [String] an attribution notice corresponding to this post def attribution_text(source = nil, name = nil, url = nil) "Source: #{source || att_source}\nLicense name: #{name || att_license_name}\n" \ diff --git a/app/models/tag.rb b/app/models/tag.rb index b3e4f4ae3..873a0ea95 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -38,6 +38,25 @@ def self.search(term) .distinct end + ## + # Find or create a tag within a given tag set, considering synonyms. If a synonym is given as +name+ then the primary + # tag for it is returned instead. + # @param name [String] A tag name to find or create. + # @param tag_set [TagSet] The tag set within which to search for or create the tag. + # @return [Array(Tag, String)] The found or created tag, and the final name used. If a synonymized name was given as + # +name+ then this will be the primary tag name. + # + # @example +name+ does not yet exist: a new Tag is created + # Tag.find_or_create_synonymized name: 'new-tag', tag_set: ... + # # => [Tag, 'new-tag'] + # + # @example +name+ already exists: the existing Tag is returned + # Tag.find_or_create_synonymized name: 'existing-tag', tag_set: ... + # # => [Tag, 'existing-tag'] + # + # @example +name+ is a synonym of 'other-tag': the Tag for 'other-tag' is returned + # Tag.find_or_create_synonymized name: 'synonym', tag_set: ... + # # => [Tag, 'other-tag'] def self.find_or_create_synonymized(name:, tag_set:) existing = Tag.find_by(name: name, tag_set: tag_set) if existing.nil?