Browse Source

Maintenance: Added methods to get list of tagged objects or references to them in backend code.

Mantas Masalskis 3 years ago
parent
commit
28829c334b

+ 41 - 0
app/models/concerns/has_tags.rb

@@ -77,4 +77,45 @@ destroy all tags of an object
     true
     true
   end
   end
 
 
+  class_methods do
+
+=begin
+
+Lists references to objects of this type with certain tag.
+Returns array containing object IDs.
+
+@param [String] tag name
+
+@example
+
+Model.tag_references('Tag') # [1, 4, ...]
+
+@return [Array<Integer>]
+
+=end
+
+    def tag_references(tag)
+      Tag
+        .tag_references(tag: tag, object: name)
+        .map { |elem| elem[1] }
+    end
+
+=begin
+
+Lists objects of this type with certain tag
+
+@param [String] tag name
+
+@example
+
+Model.tag_objects('tag')
+
+@return [ActiveRecord::Relation]
+
+=end
+
+    def tag_objects(tag)
+      where id: tag_references(tag)
+    end
+  end
 end
 end

+ 33 - 0
app/models/tag.rb

@@ -152,4 +152,37 @@ returns
        .order(:id)
        .order(:id)
        .pluck('tag_items.name')
        .pluck('tag_items.name')
   end
   end
+
+=begin
+
+Lists references to objects with certain tag. Optionally filter by type.
+Returns array containing object class name and ID.
+
+@param tag [String] tag to lookup
+@param object [String] optional name of the class to search in
+
+@example
+
+references = Tag.tag_references(
+  tag: 'Tag',
+  object: 'Ticket'
+)
+
+references # [['Ticket', 1], ['Ticket', 4], ...]
+
+@return [Array<Array<String, Integer>>]
+
+=end
+
+  def self.tag_references(tag:, object: nil)
+    tag_item = Tag::Item.find_by name: tag
+
+    return [] if tag_item.nil?
+
+    output = Tag.where(tag_item: tag_item).joins(:tag_object)
+
+    output = output.where(tag_objects: { name: object }) if object.present?
+
+    output.pluck(:'tag_objects.name', :o_id)
+  end
 end
 end

+ 33 - 0
spec/models/concerns/has_tags_examples.rb

@@ -65,4 +65,37 @@ RSpec.shared_examples 'HasTags' do
       subject.tag_list
       subject.tag_list
     end
     end
   end
   end
+
+  shared_context 'with subject and another object being tagged', current_user_id: 1 do
+    before do
+      subject.tag_add(tag)
+      Tag.tag_add(object: 'AnotherObject', o_id: 123, item: tag)
+    end
+
+    let(:tag) { 'tag_name' }
+  end
+
+  describe '.tag_references' do
+    include_context 'with subject and another object being tagged' do
+      it 'returns reference to subject' do
+        expect(described_class.tag_references(tag)).to match_array [subject.id]
+      end
+
+      it 'does not return reference to subject when called with other tag' do
+        expect(described_class.tag_references('other')).to be_blank
+      end
+    end
+  end
+
+  describe '.tag_objects' do
+    include_context 'with subject and another object being tagged' do
+      it 'returns subject' do
+        expect(described_class.tag_objects(tag)).to match_array [subject]
+      end
+
+      it 'does not return subject when called with other tag' do
+        expect(described_class.tag_objects('other')).to be_blank
+      end
+    end
+  end
 end
 end

+ 28 - 0
spec/models/tag_spec.rb

@@ -156,4 +156,32 @@ RSpec.describe Tag, type: :model do
       end
       end
     end
     end
   end
   end
+
+  describe '.tag_references' do
+    context 'with objects with a tag', current_user_id: 1 do
+      before do
+        [object_1, object_2].each do |elem|
+          described_class.tag_add object: elem.class.name, o_id: elem.id, item: tag
+        end
+      end
+
+      let(:object_1) { create(:ticket) }
+      let(:object_2) { create(:knowledge_base_answer) }
+      let(:tag) { 'foo' }
+
+      it 'returns references' do
+        expect(described_class.tag_references(tag: tag)).to match_array [
+          [object_1.class.name, object_1.id],
+          [object_2.class.name, object_2.id]
+        ]
+      end
+
+      it 'returns references for the given object type' do
+        expect(described_class.tag_references(tag: tag, object: 'Ticket')).to match_array [
+          [object_1.class.name, object_1.id]
+        ]
+      end
+    end
+
+  end
 end
 end