acts-as-taggable-on-mongoid 6.0.1.4 → 6.1.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +2 -1
  3. data/.rubocop.yml +402 -38
  4. data/.ruby-version +1 -1
  5. data/Gemfile.lock +110 -110
  6. data/README.md +103 -28
  7. data/acts-as-taggable-on-mongoid.gemspec +5 -5
  8. data/lib/acts-as-taggable-on-mongoid.rb +11 -4
  9. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_associations.rb +14 -0
  10. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_fields.rb +6 -1
  11. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_hooks.rb +68 -0
  12. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_methods.rb +36 -22
  13. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_migration.rb +46 -0
  14. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_model.rb +3 -0
  15. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_scopes.rb +5 -2
  16. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_validations.rb +3 -1
  17. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_associations.rb +20 -2
  18. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_fields.rb +6 -2
  19. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_methods.rb +4 -2
  20. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_migration.rb +46 -0
  21. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_model.rb +2 -0
  22. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_scopes.rb +9 -5
  23. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_validations.rb +4 -6
  24. data/lib/acts_as_taggable_on_mongoid/tag_list.rb +91 -4
  25. data/lib/acts_as_taggable_on_mongoid/taggable.rb +22 -3
  26. data/lib/acts_as_taggable_on_mongoid/taggable/cache.rb +30 -0
  27. data/lib/acts_as_taggable_on_mongoid/taggable/changeable.rb +5 -4
  28. data/lib/acts_as_taggable_on_mongoid/taggable/core.rb +157 -34
  29. data/lib/acts_as_taggable_on_mongoid/taggable/list_tags.rb +1 -0
  30. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition.rb +43 -50
  31. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/attributes.rb +70 -6
  32. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/changeable.rb +52 -39
  33. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/list_methods.rb +77 -0
  34. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/names.rb +12 -0
  35. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/all_tags_query.rb +1 -1
  36. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/any_tags_query.rb +1 -1
  37. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/exclude_tags_query.rb +1 -1
  38. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/match_all_tags_query.rb +1 -1
  39. data/lib/acts_as_taggable_on_mongoid/taggable/tagger_relation.rb +53 -0
  40. data/lib/acts_as_taggable_on_mongoid/taggable/utils/tag_list_diff.rb +9 -7
  41. data/lib/acts_as_taggable_on_mongoid/tagger.rb +67 -0
  42. data/lib/acts_as_taggable_on_mongoid/tagger/tag_methods.rb +74 -0
  43. data/lib/acts_as_taggable_on_mongoid/tagger_tag_list.rb +171 -0
  44. data/lib/acts_as_taggable_on_mongoid/version.rb +1 -1
  45. metadata +43 -29
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Models
5
+ module Concerns
6
+ # A module that defines methods to migrate a Tag model.
7
+ #
8
+ # Mongoid does not have a standardized migration scheme, but migrations of one kind or another
9
+ # are often a fact of life, and are in this situation because of the need to change an existing
10
+ # index.
11
+ #
12
+ # Using whatever migration methodology you prefer, you need to run the appropriate migration method
13
+ # or methods on the Tag module used by your project.
14
+ #
15
+ # The migrations are named for the ActsAsTaggableMongoid versions upon which they need to be run.
16
+ # Run the correct migration(s) for the version of ActsAsTaggableOnMongoid you are currently using
17
+ # This module does not and cannot verify the version you are migrating from nor if the migration
18
+ # has been run before. Doing so is assumed to be the responsibility of your chosen
19
+ # Migration methodology.
20
+ #
21
+ # Example:
22
+ #
23
+ # # When a migration is needed, the method "up" is called:
24
+ # def up
25
+ # TaggingModel.include ActsAsTaggableOnMongoid::Models::Concerns::TaggingMigration
26
+ # TaggingModel.atom_migrate_up_6_0_1_to_6_1_1
27
+ # end
28
+ #
29
+ # The migration methods should only be run once if possible, but every reasonable effort is made to
30
+ # ensure that the migration methods are safe to re-run.
31
+ module TaggingMigration
32
+ extend ActiveSupport::Concern
33
+
34
+ class_methods do
35
+ # :reek:UncommunicativeMethodName - The name indicates what gem versions the migration is from/to
36
+ def atom_migrate_up_6_0_1_to_6_1_1
37
+ indexes = collection.indexes
38
+ indexes.drop_one "tagging_taggable_context_tag_name" if indexes.get "tagging_taggable_context_tag_name"
39
+
40
+ create_indexes
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActsAsTaggableOnMongoid
2
4
  module Models
3
5
  module Concerns
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActsAsTaggableOnMongoid
2
4
  module Models
3
5
  module Concerns
@@ -8,12 +10,14 @@ module ActsAsTaggableOnMongoid
8
10
  DEFAULT_CONTEXT = "tags"
9
11
 
10
12
  included do
11
- # scope :owned_by, ->(owner) { where(tagger: owner) }
12
- # scope :not_owned, -> { where(tagger_id: nil, tagger_type: nil) }
13
+ # aliased scopes from ActsAsTaggable
14
+ scope :owned_by, ->(tagger) { tagged_by(tagger) }
15
+ scope :not_owned, -> { tagged_by(nil) }
13
16
 
14
- scope :by_contexts, ->(*contexts) { where(:context.in => Array.wrap(contexts.presence || DEFAULT_CONTEXT)) }
15
- scope :by_context, ->(context = DEFAULT_CONTEXT) { by_contexts(context.to_s) }
16
- scope :for_tag, ->(tag_definition) { where(taggable_type: tag_definition.owner.name).by_context(tag_definition.tag_type) }
17
+ scope :by_tag_types, ->(*tag_types) { where(:context.in => Array.wrap(tag_types.presence || DEFAULT_CONTEXT)) }
18
+ scope :by_tag_type, ->(tag_type = DEFAULT_CONTEXT) { by_tag_types(tag_type.to_s) }
19
+ scope :tagged_by, ->(tagger) { tagger ? where(tagger: tagger) : where(:tagger_id.exists => false) }
20
+ scope :for_tag, ->(tag_definition) { where(taggable_type: tag_definition.owner.name).by_tag_type(tag_definition.tag_type) }
17
21
  end
18
22
  end
19
23
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActsAsTaggableOnMongoid
2
4
  module Models
3
5
  module Concerns
@@ -8,13 +10,9 @@ module ActsAsTaggableOnMongoid
8
10
  included do
9
11
  validates :tag_name, presence: true
10
12
  validates :context, presence: true
11
- validates :tag, presence: true
12
- validates :taggable, presence: true
13
13
 
14
- # validates :tag_id, uniqueness: {scope: [:taggable_type, :taggable_id, :context, :tagger_id, :tagger_type]}
15
- validates :tag_name, uniqueness: { scope: %i[taggable_type taggable_id context] }
16
- # validates :tag_id, uniqueness: {scope: [:taggable_type, :taggable_id, :context, :tagger_id, :tagger_type]}
17
- validates :tag_id, uniqueness: { scope: %i[taggable_type taggable_id context] }
14
+ validates :tag_name, uniqueness: { scope: %i[taggable_id taggable_type context tagger_id tagger_type] }
15
+ validates :tag_id, uniqueness: { scope: %i[taggable_id taggable_type context tagger_id tagger_type] }
18
16
  end
19
17
  end
20
18
  end
@@ -12,6 +12,16 @@ module ActsAsTaggableOnMongoid
12
12
  #
13
13
  # If the input value(s) are to be parsed, then all values passed in are parsed.
14
14
  #
15
+ # Options:
16
+ # parse - True/False - indicates if all of the strings that are passed in are to be parsed
17
+ # to split them into an array of strings.
18
+ # Please note - if the passed in value is an array of strings, every string in the array
19
+ # will be parsed. If it is a single array, then just that string is parsed.
20
+ # parser - Class - A class that is used to parse the passed in strings.
21
+ # If this parameter is supplied, parse is assumed to be truthy even if it is not passed in.
22
+ # tagger - object - An object that is to be used as the Tagger for the Taggable object.
23
+ # This parameter is ignored if the tag does not support Taggers.
24
+ #
15
25
  # Examples:
16
26
  # TagList.new(tag_definition, "value 1", "value 2")
17
27
  # # > TagList<> ["value 1", "value 2"]
@@ -38,6 +48,40 @@ module ActsAsTaggableOnMongoid
38
48
  add(*args)
39
49
  end
40
50
 
51
+ class << self
52
+ def new_taggable_list(tag_definition, taggable)
53
+ list = ActsAsTaggableOnMongoid::TagList.new(tag_definition)
54
+
55
+ list.taggable = taggable
56
+
57
+ list
58
+ end
59
+ end
60
+
61
+ def dup
62
+ list = ActsAsTaggableOnMongoid::TagList.new(tag_definition, *self)
63
+ list.tagger = instance_variable_get(:@tagger) if instance_variable_defined?(:@tagger)
64
+ list.taggable = taggable
65
+
66
+ list
67
+ end
68
+
69
+ def tagger=(value)
70
+ return unless tag_definition.tagger?
71
+
72
+ instance_variable_set(:@tagger, value)
73
+ end
74
+
75
+ def tagger
76
+ return nil unless tag_definition.tagger?
77
+ return tag_definition.default_tagger(taggable) unless instance_variable_defined?(:@tagger)
78
+
79
+ tagger = instance_variable_get(:@tagger)
80
+ tagger = taggable&.public_send(tagger) if tagger.is_a?(Symbol)
81
+
82
+ instance_variable_set(:@tagger, tagger)
83
+ end
84
+
41
85
  ##
42
86
  # Add tags to the tag_list. Duplicate or blank tags will be ignored.
43
87
  # Use the <tt>:parse</tt> option to add an unparsed tag string.
@@ -53,6 +97,17 @@ module ActsAsTaggableOnMongoid
53
97
  self
54
98
  end
55
99
 
100
+ ##
101
+ # Replaces the tags with the tags passed in.
102
+ #
103
+ # Example:
104
+ # tag_list.set("Fun", "Happy")
105
+ # tag_list.set("Fun, Happy", :parse => true)
106
+ def set(*names)
107
+ clear
108
+ add(*names)
109
+ end
110
+
56
111
  # Append---Add the tag to the tag_list. This
57
112
  # expression returns the tag_list itself, so several appends
58
113
  # may be chained together.
@@ -63,7 +118,13 @@ module ActsAsTaggableOnMongoid
63
118
  # Concatenation --- Returns a new tag list built by concatenating the
64
119
  # two tag lists together to produce a third tag list.
65
120
  def +(other)
66
- TagList.new(tag_definition).add(*self).add(other)
121
+ dup.add(other)
122
+ end
123
+
124
+ # Removal --- Returns a new tag list built by removing the
125
+ # passed in tag list to produce a third tag list.
126
+ def -(other)
127
+ dup.remove(other)
67
128
  end
68
129
 
69
130
  # Appends the elements of +other_tag_list+ to +self+.
@@ -75,6 +136,27 @@ module ActsAsTaggableOnMongoid
75
136
  self
76
137
  end
77
138
 
139
+ # Appends the elements of +other_tag_list+ to +self+.
140
+ def clear
141
+ notify_will_change
142
+
143
+ super
144
+
145
+ self
146
+ end
147
+
148
+ # Appends the elements of +other_tag_list+ to +self+.
149
+ def silent_concat(other_tag_list)
150
+ temp_taggable = taggable
151
+ self.taggable = nil
152
+
153
+ concat(other_tag_list)
154
+
155
+ self.taggable = temp_taggable
156
+
157
+ self
158
+ end
159
+
78
160
  ##
79
161
  # Remove specific tags from the tag_list.
80
162
  # Use the <tt>:parse</tt> option to add an unparsed tag string.
@@ -151,13 +233,18 @@ module ActsAsTaggableOnMongoid
151
233
  self
152
234
  end
153
235
 
154
- # :reek:FeatureEnvy
155
- # :reek:DuplicateMethodCall
156
236
  def extract_and_apply_options!(args)
157
237
  dup_args = args.dup
158
238
  options = dup_args.extract_options!.dup
159
- options.assert_valid_keys :parse, :parser
160
239
 
240
+ options.assert_valid_keys :parse, :parser, :tagger
241
+
242
+ instance_variable_set(:@tagger, options[:tagger]) if options.key?(:tagger) && tag_definition.tagger?
243
+
244
+ parse_args_values(dup_args, options)
245
+ end
246
+
247
+ def parse_args_values(dup_args, options)
161
248
  options_parser = options[:parser]
162
249
  run_parser = options_parser || tag_definition.parser
163
250
 
@@ -18,7 +18,14 @@ module ActsAsTaggableOnMongoid
18
18
  # * preserve_tag_order
19
19
  # If true, the _list accessor will save and returns tags in the order they are added to the object.
20
20
  # * cached_in_model
21
- # Not currently supported
21
+ # If true, a field is added to de-normalize/cache the list into. Can also be a hash with options:
22
+ # field: The name of the field to cache the list in
23
+ # as_list: true/false - If the cached value should be an Array or a String. No order is guaranteed
24
+ # in either case.
25
+ # Defaults to true.
26
+ # * owner_id_field
27
+ # If cached_in_model is true, if a tag is owned, this is the field that will be checked for a matching
28
+ # owner ID for tag updates and deletes.
22
29
  # * force_lowercase
23
30
  # If true, values stored for tags will first be downcased to make the values effectively case-insensitive
24
31
  # * force_parameterize
@@ -34,6 +41,18 @@ module ActsAsTaggableOnMongoid
34
41
  # can be used. If custom options like `parse` or `parser` are to be used for the default, the value
35
42
  # must be passed in as an array with a hash as the last value. Like list setters, parsing is assumed.
36
43
  # Example: default: ["this, is, a, list", parser: ActsAsTaggableOnMongoid::GenericParser]
44
+ # * tagger
45
+ # Multiple variants
46
+ #
47
+ # true - If simply the value `true`, the tag list supports owners. No default owner will be used when
48
+ # setting or accessing tag_lists
49
+ # Hash - A hash of values defining default options for the tag list:
50
+ # * default_tagger
51
+ # A symbol of a method on the taggable object that owns the HashList which is used to determine
52
+ # the default owner for a list if an owner is not specified.
53
+ # * tag_list_uses_default_tagger
54
+ # true/false indicating if a non-owner method that returns a tag_list should assume the default_tagger
55
+ # or return items with no owner.
37
56
 
38
57
  ##
39
58
  # This is an alias for calling <tt>acts_as_taggable_on :tags</tt>.
@@ -110,9 +129,9 @@ module ActsAsTaggableOnMongoid
110
129
  ActsAsTaggableOnMongoid::Taggable::Changeable,
111
130
  ActsAsTaggableOnMongoid::Taggable::TaggedWith,
112
131
  # include Collection - not sure we will need as done here. Need to think more on this one.
113
- # include Cache - TODO: Add this.
114
- # include Ownership - TODO: Add this.
132
+ ActsAsTaggableOnMongoid::Taggable::Cache,
115
133
  # include Related - TODO: Add this.
134
+ ActsAsTaggableOnMongoid::Taggable::TaggerRelation,
116
135
  ActsAsTaggableOnMongoid::Taggable::ListTags].each do |include_module|
117
136
  include include_module unless included_modules.include?(include_module)
118
137
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ # A collection of generic methods which use the tag definition to perform actions.
6
+ #
7
+ # These methods are called by the individual tag generated methods to do their work so that
8
+ # the code can be defined in only one location and "shared" by all tags rather than putting the code
9
+ # and definitions into the dynamically defined methods directly.
10
+ #
11
+ # This module actually consists almost exclusively of utility functions
12
+
13
+ # :reek:FeatureEnvy
14
+ # :reek:UtilityFunction
15
+ module Cache
16
+ def save_cached_tag_lists
17
+ tag_types.each_value do |tag_definition|
18
+ next unless tag_definition.cached_in_model?
19
+ next unless tag_list_cache_set_on(tag_definition)
20
+
21
+ list = all_tags_list_on(tag_definition)
22
+
23
+ list = list.to_s unless tag_definition.cached_in_model_as_list?
24
+
25
+ public_send("#{tag_definition.cached_in_model_field}=", list)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -40,9 +40,9 @@ module ActsAsTaggableOnMongoid
40
40
  tag_types.each_value do |tag_definition|
41
41
  tag_list_name = tag_definition.tag_list_name
42
42
 
43
- next unless changed_attributes.key? tag_list_name
43
+ next unless public_send("#{tag_list_name}_changed?")
44
44
 
45
- changed_values[tag_list_name] = [changed_attributes[tag_list_name], public_send(tag_list_name)]
45
+ changed_values[tag_list_name] = public_send("#{tag_list_name}_change")
46
46
  end
47
47
 
48
48
  changed_values
@@ -60,11 +60,12 @@ module ActsAsTaggableOnMongoid
60
60
  private
61
61
 
62
62
  def attribute_will_change!(attribute_name)
63
- return super if tag_types.none? { |_tag_name, tag_definition| tag_definition.tag_list_name.to_s == attribute_name.to_s }
63
+ tag_definition = tag_types.detect { |_tag_name, tag_def| tag_def.tag_list_name.to_s == attribute_name.to_s }&.last
64
+ return super if tag_definition.blank?
64
65
 
65
66
  return if changed_attributes.key?(attribute_name)
66
67
 
67
- changed_attributes[attribute_name] = public_send(attribute_name)&.dup
68
+ changed_attributes[attribute_name] = tag_list_cache_on(tag_definition)&.dup
68
69
  end
69
70
  end
70
71
  end
@@ -22,6 +22,7 @@ module ActsAsTaggableOnMongoid
22
22
  # attr_writer :custom_contexts
23
23
 
24
24
  after_save :save_tags
25
+ before_save :save_cached_tag_lists
25
26
  end
26
27
 
27
28
  class_methods do
@@ -40,14 +41,99 @@ module ActsAsTaggableOnMongoid
40
41
  end
41
42
  end
42
43
 
43
- def apply_pre_processed_defaults
44
- super
44
+ def apply_post_processed_defaults
45
+ defaults = super
45
46
 
46
- set_tag_list_defaults
47
+ defaults |= set_tag_list_defaults
48
+
49
+ defaults
47
50
  end
48
51
 
49
52
  private
50
53
 
54
+ def set_tag_list(tag_definition, new_tags)
55
+ dup_tags = Array.wrap(new_tags).dup
56
+ options = dup_tags.extract_options!.dup
57
+ options[:parse] = options.fetch(:parse) { true }
58
+
59
+ new_list = tag_definition.parse(*dup_tags, options)
60
+ new_list.taggable = self
61
+ new_list.tagger = tag_definition.tag_list_default_tagger(self) unless options.key?(:tagger)
62
+
63
+ mark_tag_list_changed(new_list)
64
+ tag_list_set(new_list)
65
+ end
66
+
67
+ def get_tag_list_change(tag_definition)
68
+ tag_list_name = tag_definition.tag_list_name
69
+
70
+ return nil unless public_send("#{tag_list_name}_changed?")
71
+
72
+ changed_value = new_record? ? tag_definition.default_tagger_tag_list(self) : changed_attributes[tag_list_name]
73
+ current_value = tag_list_cache_on(tag_definition)
74
+
75
+ return nil if (changed_value <=> current_value)&.zero?
76
+
77
+ tag_list_change_value(tag_definition, changed_value, current_value)
78
+ end
79
+
80
+ def tag_list_change_value(tag_definition, changed_value, current_value)
81
+ if tag_definition.tagger?
82
+ [changed_value.dup, current_value.dup]
83
+ else
84
+ [changed_value[nil].dup, current_value[nil].dup]
85
+ end
86
+ end
87
+
88
+ def get_tag_list_changed(tag_definition)
89
+ tag_list_name = tag_definition.tag_list_name
90
+
91
+ return false unless changed_attributes.key?(tag_list_name)
92
+
93
+ changed_value = new_record? ? tag_definition.default_tagger_tag_list(self) : changed_attributes[tag_list_name]
94
+ current_value = tag_list_cache_on(tag_definition)
95
+
96
+ !(changed_value <=> current_value)&.zero?
97
+ end
98
+
99
+ def get_tag_list_was(tag_definition)
100
+ default_tagger = tag_definition.tag_list_default_tagger(self)
101
+ return tag_definition.default_tagger_tag_list(self)[default_tagger].dup if new_record?
102
+
103
+ tag_list_name = tag_definition.tag_list_name
104
+
105
+ if public_send "#{tag_list_name}_changed?"
106
+ changed_attributes[tag_list_name][default_tagger].dup
107
+ else
108
+ public_send(tag_list_name).dup
109
+ end
110
+ end
111
+
112
+ def get_tag_lists_was(tag_definition)
113
+ return tag_definition.default_tagger_tag_list(self).dup if new_record?
114
+
115
+ tag_list_name = tag_definition.tag_list_name
116
+
117
+ if public_send "#{tag_list_name}_changed?"
118
+ changed_attributes[tag_list_name].dup
119
+ else
120
+ public_send(tag_definition.tagger_tag_lists_name).dup
121
+ end
122
+ end
123
+
124
+ def get_tagger_list_was(tag_definition, tagger)
125
+ return nil unless tag_definition.tagger?
126
+ return tag_definition.default_tagger_tag_list(self)[tagger].dup if new_record?
127
+
128
+ tag_list_name = tag_definition.tag_list_name
129
+
130
+ if public_send "#{tag_list_name}_changed?"
131
+ changed_attributes[tag_list_name][tagger].dup
132
+ else
133
+ public_send(tag_definition.tagger_tag_list_name, tagger).dup
134
+ end
135
+ end
136
+
51
137
  def tag_list_cache_set_on(tag_definition)
52
138
  variable_name = tag_definition.tag_list_variable_name
53
139
 
@@ -66,35 +152,57 @@ module ActsAsTaggableOnMongoid
66
152
  # end
67
153
 
68
154
  instance_variable_get(variable_name) ||
69
- tag_list_set(ActsAsTaggableOnMongoid::TagList.new(tag_definition, tags_on(tag_definition).map(&:tag_name)))
155
+ tagger_tag_list_set(tagger_tag_list_from_taggings(tag_definition, all_tags_on(tag_definition)))
156
+ end
157
+
158
+ def tagger_tag_list_from_taggings(tag_definition, taggings)
159
+ tagger_tag_list = ActsAsTaggableOnMongoid::TaggerTagList.new(tag_definition, self)
160
+
161
+ taggings.each do |tagging|
162
+ tagger_tag_list[tagging.tagger].silent_concat [tagging.tag_name]
163
+ end
164
+
165
+ tagger_tag_list
70
166
  end
71
167
 
72
168
  def tag_list_on(tag_definition)
73
169
  # add_custom_context(tag_definition)
74
170
 
75
- tag_list_cache_on(tag_definition)
171
+ tag_list_cache_on(tag_definition)[tag_definition.tag_list_default_tagger(self)]
76
172
  end
77
173
 
78
174
  def all_tags_list_on(tag_definition)
79
- variable_name = tag_definition.all_tag_list_variable_name
80
- cached_variable = instance_variable_get(variable_name)
81
-
82
- return cached_variable if instance_variable_defined?(variable_name) && cached_variable
83
-
84
- instance_variable_set(variable_name, ActsAsTaggableOnMongoid::TagList.new(tag_definition, all_tags_on(tag_definition).map(&:name)).freeze)
175
+ tag_list_cache_on(tag_definition).flatten
85
176
  end
86
177
 
87
178
  ##
88
179
  # Returns all tags of a given context
89
180
  def all_tags_on(tag_definition)
90
- tag_definition.tags_table.for_tag(tag_definition).to_a
181
+ scope = public_send(tag_definition.taggings_name).where(context: tag_definition.tag_type)
182
+
183
+ # when preserving tag order, return tags in created order
184
+ # if we added the order to the association this would always apply
185
+ scope = scope.order_by(*tag_definition.taggings_order) if tag_definition.preserve_tag_order?
186
+
187
+ scope
91
188
  end
92
189
 
93
190
  ##
94
191
  # Returns all tags that are not owned of a given context
95
192
  def tags_on(tag_definition)
96
- # scope = public_send(tag_definition.taggings_name).where(context: tag_definition.tag_type, tagger_id: nil)
97
- scope = public_send(tag_definition.taggings_name).where(context: tag_definition.tag_type)
193
+ scope = public_send(tag_definition.taggings_name).where(context: tag_definition.tag_type, :tagger_id.exists => false)
194
+
195
+ # when preserving tag order, return tags in created order
196
+ # if we added the order to the association this would always apply
197
+ scope = scope.order_by(*tag_definition.taggings_order) if tag_definition.preserve_tag_order?
198
+
199
+ scope
200
+ end
201
+
202
+ ##
203
+ # Returns all tags that are owned by a given tagger of a given context
204
+ def tagger_tags_on(tagger, tag_definition)
205
+ scope = public_send(tag_definition.taggings_name).where(context: tag_definition.tag_type, tagger: tagger)
98
206
 
99
207
  # when preserving tag order, return tags in created order
100
208
  # if we added the order to the association this would always apply
@@ -105,41 +213,56 @@ module ActsAsTaggableOnMongoid
105
213
 
106
214
  def mark_tag_list_changed(new_list)
107
215
  tag_definition = new_list.tag_definition
108
- current_tag_list = public_send(tag_definition.tag_list_name)
216
+ current_tag_list = tag_list_cache_on(tag_definition)
109
217
 
110
- if (tag_definition.preserve_tag_order? && new_list != current_tag_list) ||
111
- new_list.sort != current_tag_list.sort
112
- current_tag_list.notify_will_change
113
- end
218
+ return if current_tag_list == new_list
219
+
220
+ current_tag_list.notify_will_change
221
+ end
222
+
223
+ def tagger_tag_list_set(new_list)
224
+ instance_variable_set(new_list.tag_definition.tag_list_variable_name, new_list)
114
225
  end
115
226
 
116
227
  def tag_list_set(new_list)
117
228
  # add_custom_context(tag_definition, owner)
118
229
 
119
230
  new_list.taggable = self
231
+ tag_definition = new_list.tag_definition
232
+ tagger_tag_list = ActsAsTaggableOnMongoid::TaggerTagList.new(tag_definition, self)
120
233
 
121
- instance_variable_set(new_list.tag_definition.tag_list_variable_name, new_list)
234
+ tagger_tag_list[new_list.tagger] = new_list
235
+
236
+ instance_variable_set(tag_definition.tag_list_variable_name, tagger_tag_list)
122
237
  end
123
238
 
124
239
  ##
125
240
  # Find existing tags or create non-existing tags
126
- def load_tags(tag_definition, tag_list)
127
- tag_definition.tags_table.find_or_create_all_with_like_by_name(tag_definition, tag_list)
241
+ def load_tags(tag_definition, tagger_tag_list)
242
+ tag_definition.tags_table.find_or_create_tagger_list_with_like_by_name(tag_definition, tagger_tag_list)
128
243
  end
129
244
 
130
245
  def set_tag_list_defaults
131
- return unless new_record?
246
+ return [] unless new_record?
132
247
 
248
+ defaulted_values = []
133
249
  tag_types.each_value do |tag_definition|
134
- default = tag_definition.default
250
+ next if instance_variable_defined?(tag_definition.tag_list_variable_name)
251
+
252
+ default = tag_definition.taggable_default(self)
135
253
  next unless default.present?
136
254
 
137
- tag_list_name = tag_definition.tag_list_name
138
- next if public_send(tag_list_name).present?
255
+ set_default_value(tag_definition, default)
139
256
 
140
- public_send("#{tag_list_name}=", default)
141
- changed_attributes.delete tag_list_name
257
+ defaulted_values << tag_definition.tag_list_name
142
258
  end
259
+
260
+ defaulted_values
261
+ end
262
+
263
+ def set_default_value(tag_definition, default)
264
+ public_send(tag_definition.tagger_tag_lists_name)[default.tagger] = default
265
+ changed_attributes.delete tag_definition.tag_list_name
143
266
  end
144
267
 
145
268
  def save_tags
@@ -167,11 +290,11 @@ module ActsAsTaggableOnMongoid
167
290
  end
168
291
 
169
292
  def extract_tag_list_changes(tag_definition)
170
- tag_list = tag_list_cache_on(tag_definition).uniq
293
+ tag_list = tag_list_cache_on(tag_definition)
171
294
 
172
295
  # Find existing tags or create non-existing tags:
173
296
  tags = find_or_create_tags_from_list_with_context(tag_definition, tag_list)
174
- current_tags = tags_on(tag_definition).map(&:tag).compact
297
+ current_tags = all_tags_on(tag_definition)
175
298
 
176
299
  tag_list_diff = ActsAsTaggableOnMongoid::Taggable::Utils::TagListDiff.new tag_definition: tag_definition,
177
300
  tags: tags,
@@ -210,10 +333,10 @@ module ActsAsTaggableOnMongoid
210
333
  # end
211
334
  # end
212
335
  #
213
- # @param [Array<String>] tag_list Tags to find or create
214
- # @param [Symbol] context The tag context for the tag_list
215
- def find_or_create_tags_from_list_with_context(tag_definition, tag_list)
216
- load_tags(tag_definition, tag_list)
336
+ # @param [Array<String>] tagger_tag_list Tags to find or create grouped by tagger
337
+ # @param [Symbol] tag_definition The tag context for the tag_list
338
+ def find_or_create_tags_from_list_with_context(tag_definition, tagger_tag_list)
339
+ load_tags(tag_definition, tagger_tag_list)
217
340
  end
218
341
  end
219
342
  end