Class: Tag

Inherits:
ApplicationRecord show all
Includes:
CommunityRelated
Defined in:
app/models/tag.rb

Direct Known Subclasses

TagWithPath

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationRecord

#attributes_print, fuzzy_search, match_search, #match_search, sanitize_for_search, sanitize_name, sanitize_sql_in, useful_err_msg, with_lax_group_rules

Class Method Details

.find_or_create_synonymized(name:, tag_set:) ⇒ Array(Tag, String)

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.

Examples:

name does not yet exist: a new Tag is created

Tag.find_or_create_synonymized name: 'new-tag', tag_set: ...
# => [Tag, 'new-tag']

name already exists: the existing Tag is returned

Tag.find_or_create_synonymized name: 'existing-tag', tag_set: ...
# => [Tag, 'existing-tag']

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']

Parameters:

  • name (String)

    A tag name to find or create.

  • tag_set (TagSet)

    The tag set within which to search for or create the tag.

Returns:

  • (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.



60
61
62
63
64
65
66
67
68
69
# File 'app/models/tag.rb', line 60

def self.find_or_create_synonymized(name:, tag_set:)
  existing = Tag.find_by(name: name, tag_set: tag_set)
  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

.search(term) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'app/models/tag.rb', line 21

def self.search(term)
  stripped = term.strip
  # Query to search on tags, the name is used for sorting.
  q1 = where('tags.name LIKE ?', "%#{sanitize_sql_like(stripped)}%")
       .or(where('tags.excerpt LIKE ?', "%#{sanitize_sql_like(stripped)}%"))
       .select(Arel.sql('name AS sortname, tags.*'))

  # Query to search on synonyms, the synonym name is used for sorting.
  # The order clause here actually applies to the union of q1 and q2 (so not just q2).
  q2 = joins(:tag_synonyms)
       .where('tag_synonyms.name LIKE ?', "%#{sanitize_sql_like(stripped)}%")
       .select(Arel.sql('tag_synonyms.name AS sortname, tags.*'))
       .order(Arel.sql(sanitize_sql_array(['sortname LIKE ? DESC, sortname', "#{sanitize_sql_like(stripped)}%"])))

  # Select from the union of the above queries, select only the tag columns such that we can distinct them
  from(Arel.sql("(#{q1.to_sql} UNION #{q2.to_sql}) tags"))
    .select(Tag.column_names.map { |c| "tags.#{c}" })
    .distinct
end

Instance Method Details

#all_childrenObject



71
72
73
74
75
# File 'app/models/tag.rb', line 71

def all_children
  query = File.read(Rails.root.join('db/scripts/tag_children.sql'))
  query = query.gsub('$ParentId', id.to_s)
  ActiveRecord::Base.connection.execute(query).to_a.map(&:first)
end

#parent_chainObject



77
78
79
80
81
82
83
84
85
# File 'app/models/tag.rb', line 77

def parent_chain
  Enumerator.new do |enum|
    parent_group = group
    until parent_group.nil?
      enum.yield parent_group
      parent_group = parent_group.group
    end
  end
end