acts-as-taggable-on-mongoid 6.0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.circleci/config.yml +63 -0
- data/.gitignore +54 -0
- data/.reek.yml +8 -0
- data/.rspec +2 -0
- data/.rubocop.yml +59 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +203 -0
- data/LICENSE.txt +21 -0
- data/PULL_REQUEST_TEMPLATE.md +11 -0
- data/README.md +741 -0
- data/Rakefile +8 -0
- data/acts-as-taggable-on-mongoid.gemspec +54 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/codecov.yml +3 -0
- data/config/pronto-circleci.yml +7 -0
- data/lib/acts-as-taggable-on-mongoid.rb +80 -0
- data/lib/acts_as_taggable_on_mongoid/configuration.rb +94 -0
- data/lib/acts_as_taggable_on_mongoid/default_parser.rb +120 -0
- data/lib/acts_as_taggable_on_mongoid/errors/duplicate_tag_error.rb +9 -0
- data/lib/acts_as_taggable_on_mongoid/generic_parser.rb +44 -0
- data/lib/acts_as_taggable_on_mongoid/models/tag.rb +103 -0
- data/lib/acts_as_taggable_on_mongoid/models/tagging.rb +80 -0
- data/lib/acts_as_taggable_on_mongoid/tag_list.rb +169 -0
- data/lib/acts_as_taggable_on_mongoid/taggable.rb +131 -0
- data/lib/acts_as_taggable_on_mongoid/taggable/changeable.rb +71 -0
- data/lib/acts_as_taggable_on_mongoid/taggable/core.rb +219 -0
- data/lib/acts_as_taggable_on_mongoid/taggable/list_tags.rb +45 -0
- data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition.rb +189 -0
- data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/attributes.rb +77 -0
- data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/changeable.rb +140 -0
- data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/names.rb +39 -0
- data/lib/acts_as_taggable_on_mongoid/taggable/utils/tag_list_diff.rb +121 -0
- data/lib/acts_as_taggable_on_mongoid/version.rb +5 -0
- metadata +352 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActsAsTaggableOnMongoid
|
4
|
+
module Models
|
5
|
+
# A class representing all tags that have ever been set on a model.
|
6
|
+
class Tag
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
|
10
|
+
field :name, type: String
|
11
|
+
field :taggings_count, type: Integer, default: 0
|
12
|
+
field :context, type: String
|
13
|
+
field :taggable_type, type: String
|
14
|
+
|
15
|
+
# field :type, type: String
|
16
|
+
|
17
|
+
index({ name: 1, taggable_type: 1, context: 1 }, unique: true)
|
18
|
+
|
19
|
+
### ASSOCIATIONS:
|
20
|
+
|
21
|
+
has_many :taggings, dependent: :destroy, class_name: "ActsAsTaggableOnMongoid::Models::Tagging"
|
22
|
+
|
23
|
+
### VALIDATIONS:
|
24
|
+
|
25
|
+
validates :name, presence: true
|
26
|
+
validates :context, presence: true
|
27
|
+
validates :taggable_type, presence: true
|
28
|
+
validates :name, uniqueness: { scope: %i[context taggable_type] }
|
29
|
+
|
30
|
+
### SCOPES:
|
31
|
+
scope :most_used, ->(limit = 20) { order("taggings_count desc").limit(limit) }
|
32
|
+
scope :least_used, ->(limit = 20) { order("taggings_count asc").limit(limit) }
|
33
|
+
|
34
|
+
scope :named, ->(name) { where(name: as_8bit_ascii(name)) }
|
35
|
+
scope :named_any, ->(*names) { where(:name.in => names.map { |name| as_8bit_ascii(name) }) }
|
36
|
+
scope :named_like, ->(name) { where(name: /#{as_8bit_ascii(name)}/i) }
|
37
|
+
scope :named_like_any, ->(*names) { where(:name.in => names.map { |name| /#{as_8bit_ascii(name)}/i }) }
|
38
|
+
scope :for_context, ->(context) { where(context: context) }
|
39
|
+
scope :for_taggable_class, ->(taggable_type) { where(taggable_type: taggable_type.name) }
|
40
|
+
scope :for_tag, ->(tag_definition) { for_taggable_class(tag_definition.owner).for_context(tag_definition.tag_type) }
|
41
|
+
|
42
|
+
### CLASS METHODS:
|
43
|
+
|
44
|
+
class << self
|
45
|
+
def find_or_create_all_with_like_by_name(tag_definition, *list)
|
46
|
+
list = ActsAsTaggableOnMongoid::TagList.new(tag_definition, *Array.wrap(list).flatten)
|
47
|
+
|
48
|
+
return [] if list.empty?
|
49
|
+
|
50
|
+
list.map do |tag_name|
|
51
|
+
begin
|
52
|
+
tries ||= 3
|
53
|
+
|
54
|
+
existing_tag = tag_definition.tags_table.for_tag(tag_definition).named(tag_name).first
|
55
|
+
|
56
|
+
existing_tag || create_tag(tag_definition, tag_name)
|
57
|
+
rescue Mongoid::Errors::Validations
|
58
|
+
# :nocov:
|
59
|
+
if (tries -= 1).positive?
|
60
|
+
retry
|
61
|
+
end
|
62
|
+
|
63
|
+
raise ActsAsTaggableOnMongoid::Errors::DuplicateTagError.new, "'#{tag_name}' has already been taken"
|
64
|
+
# :nocov:
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def create_tag(tag_definition, name)
|
72
|
+
tag_definition.tags_table.create(name: name,
|
73
|
+
context: tag_definition.tag_type,
|
74
|
+
taggable_type: tag_definition.owner.name)
|
75
|
+
end
|
76
|
+
|
77
|
+
def as_8bit_ascii(string)
|
78
|
+
string = string.to_s
|
79
|
+
if defined?(Encoding)
|
80
|
+
string.dup.force_encoding("BINARY")
|
81
|
+
else
|
82
|
+
# :nocov:
|
83
|
+
string.mb_chars
|
84
|
+
# :nocov:
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
### INSTANCE METHODS:
|
90
|
+
|
91
|
+
def ==(other)
|
92
|
+
super || (other.class == self.class &&
|
93
|
+
name == other.name &&
|
94
|
+
context == other.context &&
|
95
|
+
taggable_type == other.taggable_type)
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_s
|
99
|
+
name
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActsAsTaggableOnMongoid
|
4
|
+
module Models
|
5
|
+
# A class representing the actual tags assigned to a particular model object
|
6
|
+
class Tagging
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
|
10
|
+
DEFAULT_CONTEXT = "tags"
|
11
|
+
|
12
|
+
after_save :tagging_saved
|
13
|
+
after_destroy :tagging_destroyed
|
14
|
+
|
15
|
+
field :tag_name, type: String
|
16
|
+
field :context, type: String
|
17
|
+
|
18
|
+
belongs_to :tag, counter_cache: true, inverse_of: :taggings
|
19
|
+
belongs_to :taggable, polymorphic: true
|
20
|
+
# belongs_to :tagger, { polymorphic: true, optional: true }
|
21
|
+
|
22
|
+
# If/when adding the concept of a tagger, this index will need to be changed.
|
23
|
+
index({ taggable_id: 1, taggable_type: 1, context: 1, tag_name: 1 }, unique: true, name: "tagging_taggable_context_tag_name")
|
24
|
+
index(tag_name: 1)
|
25
|
+
index(tag_id: 1, tag_type: 1)
|
26
|
+
|
27
|
+
# scope :owned_by, ->(owner) { where(tagger: owner) }
|
28
|
+
# scope :not_owned, -> { where(tagger_id: nil, tagger_type: nil) }
|
29
|
+
|
30
|
+
scope :by_contexts, ->(*contexts) { where(:context.in => Array.wrap(contexts.presence || DEFAULT_CONTEXT)) }
|
31
|
+
scope :by_context, ->(context = DEFAULT_CONTEXT) { by_contexts(context.to_s) }
|
32
|
+
scope :for_tag, ->(tag_definition) { where(taggable_type: tag_definition.owner.name).by_context(tag_definition.tag_type) }
|
33
|
+
|
34
|
+
validates :tag_name, presence: true
|
35
|
+
validates :context, presence: true
|
36
|
+
validates :tag, presence: true
|
37
|
+
validates :taggable, presence: true
|
38
|
+
|
39
|
+
# validates :tag_id, uniqueness: {scope: [:taggable_type, :taggable_id, :context, :tagger_id, :tagger_type]}
|
40
|
+
validates :tag_name, uniqueness: { scope: %i[taggable_type taggable_id context] }
|
41
|
+
# validates :tag_id, uniqueness: {scope: [:taggable_type, :taggable_id, :context, :tagger_id, :tagger_type]}
|
42
|
+
validates :tag_id, uniqueness: { scope: %i[taggable_type taggable_id context] }
|
43
|
+
|
44
|
+
after_destroy :remove_unused_tags
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def remove_unused_tags
|
49
|
+
return nil unless taggable
|
50
|
+
|
51
|
+
tag_definition = taggable.tag_types[context]
|
52
|
+
|
53
|
+
return unless tag_definition&.remove_unused_tags?
|
54
|
+
|
55
|
+
tag.destroy if tag.reload.taggings_count.zero?
|
56
|
+
end
|
57
|
+
|
58
|
+
def tagging_saved
|
59
|
+
tag_definition = taggable.tag_types[context]
|
60
|
+
|
61
|
+
return unless tag_definition
|
62
|
+
|
63
|
+
tag_list = taggable.public_send(tag_definition.tag_list_name)
|
64
|
+
tag_list.add_tagging(self)
|
65
|
+
end
|
66
|
+
|
67
|
+
def tagging_destroyed
|
68
|
+
taggable_was = taggable_type_was.constantize.where(id: taggable_id_was).first
|
69
|
+
|
70
|
+
return unless taggable_was
|
71
|
+
|
72
|
+
tag_definition = taggable_was.tag_types[context_was]
|
73
|
+
|
74
|
+
return unless tag_definition
|
75
|
+
|
76
|
+
taggable_was.public_send(tag_definition.tag_list_name).remove(tag_name_was)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# require "active_support/core_ext/module/delegation"
|
4
|
+
|
5
|
+
module ActsAsTaggableOnMongoid
|
6
|
+
# A list of tags. The TagList must be initialized with a tag definition so that it knows how to clean
|
7
|
+
# the list properly and to convert the list to a string.
|
8
|
+
#
|
9
|
+
# All methods that add objects to the list (initialization, concat, etc.) optionally take an array of values including
|
10
|
+
# options to parse the values and to optionally specifiy the parser to use. If no parser is specified, then
|
11
|
+
# parser for the tag_definition is used.
|
12
|
+
#
|
13
|
+
# If the input value(s) are to be parsed, then all values passed in are parsed.
|
14
|
+
#
|
15
|
+
# Examples:
|
16
|
+
# TagList.new(tag_definition, "value 1", "value 2")
|
17
|
+
# # > TagList<> ["value 1", "value 2"]
|
18
|
+
#
|
19
|
+
# TagList.new(tag_definition, "value 1, value 2", parse: true)
|
20
|
+
# # > TagList<> ["value 1", "value 2"]
|
21
|
+
#
|
22
|
+
# TagList.new(tag_definition, "value 1, value 2", "value 3, value 4", parse: true)
|
23
|
+
# # > TagList<> ["value 1", "value 2", "value 3", "value 4"]
|
24
|
+
#
|
25
|
+
# TagList.new(tag_definition, "value 1, value 2", "value 3, value 4", parser: ActsAsTaggableOnMongoid::GenericParser)
|
26
|
+
# # > TagList<> ["value 1", "value 2", "value 3", "value 4"]
|
27
|
+
|
28
|
+
# :reek:MissingSafeMethod
|
29
|
+
# :reek:SubclassedFromCoreClass
|
30
|
+
class TagList < Array
|
31
|
+
# :reek:Attribute
|
32
|
+
attr_accessor :taggable
|
33
|
+
attr_reader :tag_definition
|
34
|
+
|
35
|
+
def initialize(tag_definition, *args)
|
36
|
+
@tag_definition = tag_definition
|
37
|
+
|
38
|
+
add(*args)
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Add tags to the tag_list. Duplicate or blank tags will be ignored.
|
43
|
+
# Use the <tt>:parse</tt> option to add an unparsed tag string.
|
44
|
+
#
|
45
|
+
# Example:
|
46
|
+
# tag_list.add("Fun", "Happy")
|
47
|
+
# tag_list.add("Fun, Happy", :parse => true)
|
48
|
+
def add(*names)
|
49
|
+
extract_and_apply_options!(names)
|
50
|
+
concat(names)
|
51
|
+
clean!
|
52
|
+
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# Append---Add the tag to the tag_list. This
|
57
|
+
# expression returns the tag_list itself, so several appends
|
58
|
+
# may be chained together.
|
59
|
+
def <<(obj)
|
60
|
+
add(obj)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Concatenation --- Returns a new tag list built by concatenating the
|
64
|
+
# two tag lists together to produce a third tag list.
|
65
|
+
def +(other)
|
66
|
+
TagList.new(tag_definition).add(*self).add(other)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Appends the elements of +other_tag_list+ to +self+.
|
70
|
+
def concat(other_tag_list)
|
71
|
+
notify_will_change
|
72
|
+
|
73
|
+
super(other_tag_list).send(:clean!)
|
74
|
+
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Remove specific tags from the tag_list.
|
80
|
+
# Use the <tt>:parse</tt> option to add an unparsed tag string.
|
81
|
+
#
|
82
|
+
# Example:
|
83
|
+
# tag_list.remove("Sad", "Lonely")
|
84
|
+
# tag_list.remove("Sad, Lonely", :parse => true)
|
85
|
+
def remove(*names)
|
86
|
+
remove_list = ActsAsTaggableOnMongoid::TagList.new(tag_definition, *names)
|
87
|
+
|
88
|
+
notify_will_change
|
89
|
+
|
90
|
+
delete_if { |name| remove_list.include?(name) }
|
91
|
+
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Transform the tag_list into a tag string suitable for editing in a form.
|
97
|
+
# The tags are joined with <tt>TagList.delimiter</tt> and quoted if necessary.
|
98
|
+
#
|
99
|
+
# Example:
|
100
|
+
# tag_list = TagList.new("Round", "Square,Cube")
|
101
|
+
# tag_list.to_s # 'Round, "Square,Cube"'
|
102
|
+
def to_s
|
103
|
+
tag_definition.parser.new(*self).to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
def notify_will_change
|
107
|
+
return unless taggable
|
108
|
+
|
109
|
+
taggable.tag_list_on_changed tag_definition
|
110
|
+
end
|
111
|
+
|
112
|
+
# :reek:ManualDispatch
|
113
|
+
def ==(other)
|
114
|
+
if tag_definition.preserve_tag_order?
|
115
|
+
super
|
116
|
+
elsif other.respond_to?(:sort)
|
117
|
+
self&.sort == other.sort
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_tagging(tagging)
|
122
|
+
orig_taggable = taggable
|
123
|
+
@taggable = nil
|
124
|
+
|
125
|
+
begin
|
126
|
+
tag = tagging.tag_name
|
127
|
+
|
128
|
+
self << tag unless include?(tag)
|
129
|
+
ensure
|
130
|
+
@taggable = orig_taggable
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def clean!
|
137
|
+
reject!(&:blank?)
|
138
|
+
|
139
|
+
map!(&:to_s)
|
140
|
+
map!(&:strip)
|
141
|
+
|
142
|
+
conditional_clean_rules
|
143
|
+
end
|
144
|
+
|
145
|
+
def conditional_clean_rules
|
146
|
+
map! { |tag| tag.mb_chars.downcase.to_s } if tag_definition.force_lowercase?
|
147
|
+
map!(&:parameterize) if tag_definition.force_parameterize?
|
148
|
+
|
149
|
+
uniq!
|
150
|
+
|
151
|
+
self
|
152
|
+
end
|
153
|
+
|
154
|
+
# :reek:FeatureEnvy
|
155
|
+
# :reek:DuplicateMethodCall
|
156
|
+
def extract_and_apply_options!(args)
|
157
|
+
options = args.extract_options!
|
158
|
+
options.assert_valid_keys :parse, :parser
|
159
|
+
|
160
|
+
options_parser = options[:parser]
|
161
|
+
run_parser = options_parser || tag_definition.parser
|
162
|
+
|
163
|
+
args.flatten!
|
164
|
+
args.map! { |argument| run_parser.new(argument).parse } if options[:parse] || options_parser
|
165
|
+
|
166
|
+
args.flatten!
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActsAsTaggableOnMongoid
|
4
|
+
# This module defines the class methods to be added to the Mongoid model so that
|
5
|
+
# tags can be defined on and added to a model.
|
6
|
+
#
|
7
|
+
# When a tag is added to a model, additional modules will be included to add methods that
|
8
|
+
# are needed only if a tag is actually being used.
|
9
|
+
module Taggable
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/BlockLength
|
13
|
+
|
14
|
+
class_methods do
|
15
|
+
# Options include:
|
16
|
+
# * parser
|
17
|
+
# The class to be used to parse strings.
|
18
|
+
# * preserve_tag_order
|
19
|
+
# If true, the _list accessor will save and returns tags in the order they are added to the object.
|
20
|
+
# * cached_in_model
|
21
|
+
# Not currently supported
|
22
|
+
# * force_lowercase
|
23
|
+
# If true, values stored for tags will first be downcased to make the values effectively case-insensitive
|
24
|
+
# * force_parameterize
|
25
|
+
# If true, values stored for tags will be parameterized
|
26
|
+
# * remove_unused_tags
|
27
|
+
# If true, when there are no more taggings for a tag, the tag will be destroyed
|
28
|
+
# * tags_table
|
29
|
+
# The class to use for Tags
|
30
|
+
# * taggings_table
|
31
|
+
# The class to use for Taggings
|
32
|
+
# * default
|
33
|
+
# A default value. Any value that can be used for list assignment or adding values to a list
|
34
|
+
# can be used. If custom options like `parse` or `parser` are to be used for the default, the value
|
35
|
+
# must be passed in as an array with a hash as the last value. Like list setters, parsing is assumed.
|
36
|
+
# Example: default: ["this, is, a, list", parser: ActsAsTaggableOnMongoid::GenericParser]
|
37
|
+
|
38
|
+
##
|
39
|
+
# This is an alias for calling <tt>acts_as_taggable_on :tags</tt>.
|
40
|
+
#
|
41
|
+
# Example:
|
42
|
+
# class Book < ActiveRecord::Base
|
43
|
+
# acts_as_taggable
|
44
|
+
# end
|
45
|
+
def acts_as_taggable(options = {})
|
46
|
+
acts_as_taggable_on :tags, options
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# This is an alias for calling <tt>acts_as_ordered_taggable_on :tags</tt>.
|
51
|
+
#
|
52
|
+
# Example:
|
53
|
+
# class Book < ActiveRecord::Base
|
54
|
+
# acts_as_ordered_taggable
|
55
|
+
# end
|
56
|
+
def acts_as_ordered_taggable(options = {})
|
57
|
+
acts_as_ordered_taggable_on :tags, options
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Make a model taggable on specified contexts.
|
62
|
+
#
|
63
|
+
# @param [Array] tag_types An array of taggable contexts
|
64
|
+
#
|
65
|
+
# Example:
|
66
|
+
# class User < ActiveRecord::Base
|
67
|
+
# acts_as_taggable_on :languages, :skills
|
68
|
+
# end
|
69
|
+
def acts_as_taggable_on(*tag_types)
|
70
|
+
taggable_on(*tag_types)
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Make a model taggable on specified contexts
|
75
|
+
# and preserves the order in which tags are created.
|
76
|
+
#
|
77
|
+
# An alias for acts_as_taggable_on *tag_types, preserve_tag_order: true
|
78
|
+
#
|
79
|
+
# @param [Array] tag_types An array of taggable contexts
|
80
|
+
#
|
81
|
+
# Example:
|
82
|
+
# class User < ActiveRecord::Base
|
83
|
+
# acts_as_ordered_taggable_on :languages, :skills
|
84
|
+
# end
|
85
|
+
def acts_as_ordered_taggable_on(*tag_types)
|
86
|
+
options = tag_types.extract_options!
|
87
|
+
|
88
|
+
taggable_on(*tag_types, options.merge(preserve_tag_order: true))
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Make a model taggable on specified contexts
|
94
|
+
# and optionally preserves the order in which tags are created
|
95
|
+
#
|
96
|
+
# Separate methods used above for backwards compatibility
|
97
|
+
# so that the original acts_as_taggable_on method is unaffected
|
98
|
+
# as it's not possible to add another argument to the method
|
99
|
+
# without the tag_types being enclosed in square brackets
|
100
|
+
#
|
101
|
+
# NB: method overridden in core module in order to create tag type
|
102
|
+
# associations and methods after this logic has executed
|
103
|
+
#
|
104
|
+
def taggable_on(*tag_types)
|
105
|
+
# if we are actually defining tags on a module, add these modules to add hooks and global methods
|
106
|
+
# used by tagging. We only add them dynamically like this so that they don't bloat the model
|
107
|
+
# and add hooks/callbacks that aren't needed without tags.
|
108
|
+
[ActsAsTaggableOnMongoid::Taggable::Core,
|
109
|
+
ActsAsTaggableOnMongoid::Taggable::Changeable,
|
110
|
+
# include Collection - not sure we will need as done here. Need to think more on this one.
|
111
|
+
# include Cache - TODO: Add this.
|
112
|
+
# include Ownership - TODO: Add this.
|
113
|
+
# include Related - TODO: Add this.
|
114
|
+
ActsAsTaggableOnMongoid::Taggable::ListTags].each do |include_module|
|
115
|
+
include include_module unless included_modules.include?(include_module)
|
116
|
+
end
|
117
|
+
|
118
|
+
options = tag_types.extract_options!
|
119
|
+
tag_types.flatten!
|
120
|
+
|
121
|
+
tag_types.each do |tag_type|
|
122
|
+
next if tag_type.blank?
|
123
|
+
|
124
|
+
define_tag tag_type, options
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# rubocop:enable Metrics/BlockLength
|
130
|
+
end
|
131
|
+
end
|