acts-as-taggable-on 8.1.0 → 9.0.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 +4 -4
- data/.github/workflows/spec.yml +15 -34
- data/Appraisals +13 -13
- data/CHANGELOG.md +17 -3
- data/README.md +6 -6
- data/acts-as-taggable-on.gemspec +2 -2
- data/db/migrate/1_acts_as_taggable_on_migration.rb +5 -8
- data/db/migrate/2_add_missing_unique_indices.rb +6 -8
- data/db/migrate/3_add_taggings_counter_cache_to_tags.rb +3 -6
- data/db/migrate/4_add_missing_taggable_index.rb +5 -7
- data/db/migrate/5_change_collation_for_tag_names.rb +4 -6
- data/db/migrate/6_add_missing_indexes_on_taggings.rb +15 -13
- data/db/migrate/7_add_tenant_to_taggings.rb +7 -10
- data/docker-compose.yml +15 -0
- data/gemfiles/activerecord_6.0.gemfile +5 -8
- data/gemfiles/activerecord_6.1.gemfile +3 -8
- data/gemfiles/{activerecord_5.0.gemfile → activerecord_7.0.gemfile} +6 -9
- data/lib/acts_as_taggable_on/default_parser.rb +8 -10
- data/lib/acts_as_taggable_on/engine.rb +2 -0
- data/lib/acts_as_taggable_on/generic_parser.rb +2 -0
- data/lib/acts_as_taggable_on/tag.rb +30 -30
- data/lib/acts_as_taggable_on/tag_list.rb +8 -11
- data/lib/acts_as_taggable_on/taggable/cache.rb +64 -62
- data/lib/acts_as_taggable_on/taggable/collection.rb +178 -142
- data/lib/acts_as_taggable_on/taggable/core.rb +248 -244
- data/lib/acts_as_taggable_on/taggable/ownership.rb +110 -98
- data/lib/acts_as_taggable_on/taggable/related.rb +60 -47
- data/lib/acts_as_taggable_on/taggable/tag_list_type.rb +6 -2
- data/lib/acts_as_taggable_on/taggable/tagged_with_query/all_tags_query.rb +110 -106
- data/lib/acts_as_taggable_on/taggable/tagged_with_query/any_tags_query.rb +57 -53
- data/lib/acts_as_taggable_on/taggable/tagged_with_query/exclude_tags_query.rb +63 -60
- data/lib/acts_as_taggable_on/taggable/tagged_with_query/query_base.rb +54 -46
- data/lib/acts_as_taggable_on/taggable/tagged_with_query.rb +14 -8
- data/lib/acts_as_taggable_on/taggable.rb +14 -14
- data/lib/acts_as_taggable_on/tagger.rb +9 -5
- data/lib/acts_as_taggable_on/tagging.rb +6 -4
- data/lib/acts_as_taggable_on/tags_helper.rb +3 -1
- data/lib/acts_as_taggable_on/utils.rb +4 -2
- data/lib/acts_as_taggable_on/version.rb +3 -1
- data/spec/support/database.rb +36 -26
- metadata +13 -14
- data/gemfiles/activerecord_5.1.gemfile +0 -21
- data/gemfiles/activerecord_5.2.gemfile +0 -21
@@ -1,48 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'tagged_with_query'
|
2
4
|
require_relative 'tag_list_type'
|
3
5
|
|
4
|
-
module ActsAsTaggableOn
|
5
|
-
module
|
6
|
+
module ActsAsTaggableOn
|
7
|
+
module Taggable
|
8
|
+
module Core
|
9
|
+
def self.included(base)
|
10
|
+
base.extend ActsAsTaggableOn::Taggable::Core::ClassMethods
|
6
11
|
|
7
|
-
|
8
|
-
|
12
|
+
base.class_eval do
|
13
|
+
attr_writer :custom_contexts
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
after_save :save_tags
|
13
|
-
end
|
15
|
+
after_save :save_tags
|
16
|
+
end
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
base.initialize_acts_as_taggable_on_core
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
21
|
+
module ClassMethods
|
22
|
+
def initialize_acts_as_taggable_on_core
|
23
|
+
include taggable_mixin
|
24
|
+
tag_types.map(&:to_s).each do |tags_type|
|
25
|
+
tag_type = tags_type.to_s.singularize
|
26
|
+
context_taggings = "#{tag_type}_taggings".to_sym
|
27
|
+
context_tags = tags_type.to_sym
|
28
|
+
taggings_order = (preserve_tag_order? ? "#{ActsAsTaggableOn::Tagging.table_name}.id" : [])
|
29
|
+
|
30
|
+
class_eval do
|
31
|
+
# when preserving tag order, include order option so that for a 'tags' context
|
32
|
+
# the associations tag_taggings & tags are always returned in created order
|
33
|
+
has_many context_taggings, -> { includes(:tag).order(taggings_order).where(context: tags_type) },
|
34
|
+
as: :taggable,
|
35
|
+
class_name: 'ActsAsTaggableOn::Tagging',
|
36
|
+
dependent: :destroy,
|
37
|
+
after_add: :dirtify_tag_list,
|
38
|
+
after_remove: :dirtify_tag_list
|
39
|
+
|
40
|
+
has_many context_tags, -> { order(taggings_order) },
|
41
|
+
class_name: 'ActsAsTaggableOn::Tag',
|
42
|
+
through: context_taggings,
|
43
|
+
source: :tag
|
44
|
+
|
45
|
+
attribute "#{tags_type.singularize}_list".to_sym, ActsAsTaggableOn::Taggable::TagListType.new
|
46
|
+
end
|
44
47
|
|
45
|
-
|
48
|
+
taggable_mixin.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
46
49
|
def #{tag_type}_list
|
47
50
|
tag_list_on('#{tags_type}')
|
48
51
|
end
|
@@ -51,12 +54,8 @@ module ActsAsTaggableOn::Taggable
|
|
51
54
|
parsed_new_list = ActsAsTaggableOn.default_parser.new(new_tags).parse
|
52
55
|
|
53
56
|
if self.class.preserve_tag_order? || (parsed_new_list.sort != #{tag_type}_list.sort)
|
54
|
-
|
55
|
-
|
56
|
-
else
|
57
|
-
unless #{tag_type}_list_changed?
|
58
|
-
@attributes["#{tag_type}_list"] = ActiveModel::Attribute.from_user("#{tag_type}_list", #{tag_type}_list, ActsAsTaggableOn::Taggable::TagListType.new)
|
59
|
-
end
|
57
|
+
unless #{tag_type}_list_changed?
|
58
|
+
@attributes["#{tag_type}_list"] = ActiveModel::Attribute.from_user("#{tag_type}_list", #{tag_type}_list, ActsAsTaggableOn::Taggable::TagListType.new)
|
60
59
|
end
|
61
60
|
write_attribute("#{tag_type}_list", parsed_new_list)
|
62
61
|
end
|
@@ -72,263 +71,268 @@ module ActsAsTaggableOn::Taggable
|
|
72
71
|
def dirtify_tag_list(tagging)
|
73
72
|
attribute_will_change! tagging.context.singularize+"_list"
|
74
73
|
end
|
75
|
-
|
74
|
+
RUBY
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def taggable_on(preserve_tag_order, *tag_types)
|
79
|
+
super(preserve_tag_order, *tag_types)
|
80
|
+
initialize_acts_as_taggable_on_core
|
76
81
|
end
|
77
|
-
end
|
78
82
|
|
79
|
-
|
80
|
-
|
81
|
-
|
83
|
+
# all column names are necessary for PostgreSQL group clause
|
84
|
+
def grouped_column_names_for(object)
|
85
|
+
object.column_names.map { |column| "#{object.table_name}.#{column}" }.join(', ')
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Return a scope of objects that are tagged with the specified tags.
|
90
|
+
#
|
91
|
+
# @param tags The tags that we want to query for
|
92
|
+
# @param [Hash] options A hash of options to alter you query:
|
93
|
+
# * <tt>:exclude</tt> - if set to true, return objects that are *NOT* tagged with the specified tags
|
94
|
+
# * <tt>:any</tt> - if set to true, return objects that are tagged with *ANY* of the specified tags
|
95
|
+
# * <tt>:order_by_matching_tag_count</tt> - if set to true and used with :any, sort by objects matching the most tags, descending
|
96
|
+
# * <tt>:match_all</tt> - if set to true, return objects that are *ONLY* tagged with the specified tags
|
97
|
+
# * <tt>:owned_by</tt> - return objects that are *ONLY* owned by the owner
|
98
|
+
# * <tt>:start_at</tt> - Restrict the tags to those created after a certain time
|
99
|
+
# * <tt>:end_at</tt> - Restrict the tags to those created before a certain time
|
100
|
+
#
|
101
|
+
# Example:
|
102
|
+
# User.tagged_with(["awesome", "cool"]) # Users that are tagged with awesome and cool
|
103
|
+
# User.tagged_with(["awesome", "cool"], :exclude => true) # Users that are not tagged with awesome or cool
|
104
|
+
# User.tagged_with(["awesome", "cool"], :any => true) # Users that are tagged with awesome or cool
|
105
|
+
# User.tagged_with(["awesome", "cool"], :any => true, :order_by_matching_tag_count => true) # Sort by users who match the most tags, descending
|
106
|
+
# User.tagged_with(["awesome", "cool"], :match_all => true) # Users that are tagged with just awesome and cool
|
107
|
+
# User.tagged_with(["awesome", "cool"], :owned_by => foo ) # Users that are tagged with just awesome and cool by 'foo'
|
108
|
+
# User.tagged_with(["awesome", "cool"], :owned_by => foo, :start_at => Date.today ) # Users that are tagged with just awesome, cool by 'foo' and starting today
|
109
|
+
def tagged_with(tags, options = {})
|
110
|
+
tag_list = ActsAsTaggableOn.default_parser.new(tags).parse
|
111
|
+
options = options.dup
|
112
|
+
|
113
|
+
return none if tag_list.empty?
|
114
|
+
|
115
|
+
::ActsAsTaggableOn::Taggable::TaggedWithQuery.build(self, ActsAsTaggableOn::Tag, ActsAsTaggableOn::Tagging,
|
116
|
+
tag_list, options)
|
117
|
+
end
|
118
|
+
|
119
|
+
def is_taggable?
|
120
|
+
true
|
121
|
+
end
|
122
|
+
|
123
|
+
def taggable_mixin
|
124
|
+
@taggable_mixin ||= Module.new
|
125
|
+
end
|
82
126
|
end
|
83
127
|
|
84
128
|
# all column names are necessary for PostgreSQL group clause
|
85
129
|
def grouped_column_names_for(object)
|
86
|
-
|
130
|
+
self.class.grouped_column_names_for(object)
|
87
131
|
end
|
88
132
|
|
89
|
-
|
90
|
-
|
91
|
-
#
|
92
|
-
# @param tags The tags that we want to query for
|
93
|
-
# @param [Hash] options A hash of options to alter you query:
|
94
|
-
# * <tt>:exclude</tt> - if set to true, return objects that are *NOT* tagged with the specified tags
|
95
|
-
# * <tt>:any</tt> - if set to true, return objects that are tagged with *ANY* of the specified tags
|
96
|
-
# * <tt>:order_by_matching_tag_count</tt> - if set to true and used with :any, sort by objects matching the most tags, descending
|
97
|
-
# * <tt>:match_all</tt> - if set to true, return objects that are *ONLY* tagged with the specified tags
|
98
|
-
# * <tt>:owned_by</tt> - return objects that are *ONLY* owned by the owner
|
99
|
-
# * <tt>:start_at</tt> - Restrict the tags to those created after a certain time
|
100
|
-
# * <tt>:end_at</tt> - Restrict the tags to those created before a certain time
|
101
|
-
#
|
102
|
-
# Example:
|
103
|
-
# User.tagged_with(["awesome", "cool"]) # Users that are tagged with awesome and cool
|
104
|
-
# User.tagged_with(["awesome", "cool"], :exclude => true) # Users that are not tagged with awesome or cool
|
105
|
-
# User.tagged_with(["awesome", "cool"], :any => true) # Users that are tagged with awesome or cool
|
106
|
-
# User.tagged_with(["awesome", "cool"], :any => true, :order_by_matching_tag_count => true) # Sort by users who match the most tags, descending
|
107
|
-
# User.tagged_with(["awesome", "cool"], :match_all => true) # Users that are tagged with just awesome and cool
|
108
|
-
# User.tagged_with(["awesome", "cool"], :owned_by => foo ) # Users that are tagged with just awesome and cool by 'foo'
|
109
|
-
# User.tagged_with(["awesome", "cool"], :owned_by => foo, :start_at => Date.today ) # Users that are tagged with just awesome, cool by 'foo' and starting today
|
110
|
-
def tagged_with(tags, options = {})
|
111
|
-
tag_list = ActsAsTaggableOn.default_parser.new(tags).parse
|
112
|
-
options = options.dup
|
113
|
-
|
114
|
-
return none if tag_list.empty?
|
115
|
-
|
116
|
-
::ActsAsTaggableOn::Taggable::TaggedWithQuery.build(self, ActsAsTaggableOn::Tag, ActsAsTaggableOn::Tagging, tag_list, options)
|
133
|
+
def custom_contexts
|
134
|
+
@custom_contexts ||= taggings.map(&:context).uniq
|
117
135
|
end
|
118
136
|
|
119
137
|
def is_taggable?
|
120
|
-
|
138
|
+
self.class.is_taggable?
|
121
139
|
end
|
122
140
|
|
123
|
-
def
|
124
|
-
|
141
|
+
def add_custom_context(value)
|
142
|
+
unless custom_contexts.include?(value.to_s) || self.class.tag_types.map(&:to_s).include?(value.to_s)
|
143
|
+
custom_contexts << value.to_s
|
144
|
+
end
|
125
145
|
end
|
126
|
-
end
|
127
|
-
|
128
|
-
# all column names are necessary for PostgreSQL group clause
|
129
|
-
def grouped_column_names_for(object)
|
130
|
-
self.class.grouped_column_names_for(object)
|
131
|
-
end
|
132
146
|
|
133
|
-
|
134
|
-
|
135
|
-
|
147
|
+
def cached_tag_list_on(context)
|
148
|
+
self["cached_#{context.to_s.singularize}_list"]
|
149
|
+
end
|
136
150
|
|
137
|
-
|
138
|
-
|
139
|
-
|
151
|
+
def tag_list_cache_set_on(context)
|
152
|
+
variable_name = "@#{context.to_s.singularize}_list"
|
153
|
+
instance_variable_defined?(variable_name) && instance_variable_get(variable_name)
|
154
|
+
end
|
140
155
|
|
141
|
-
|
142
|
-
|
143
|
-
|
156
|
+
def tag_list_cache_on(context)
|
157
|
+
variable_name = "@#{context.to_s.singularize}_list"
|
158
|
+
if instance_variable_get(variable_name)
|
159
|
+
instance_variable_get(variable_name)
|
160
|
+
elsif cached_tag_list_on(context) && ensure_included_cache_methods! && self.class.caching_tag_list_on?(context)
|
161
|
+
instance_variable_set(variable_name, ActsAsTaggableOn.default_parser.new(cached_tag_list_on(context)).parse)
|
162
|
+
else
|
163
|
+
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(tags_on(context).map(&:name)))
|
164
|
+
end
|
165
|
+
end
|
144
166
|
|
145
|
-
|
146
|
-
|
147
|
-
|
167
|
+
def tag_list_on(context)
|
168
|
+
add_custom_context(context)
|
169
|
+
tag_list_cache_on(context)
|
170
|
+
end
|
148
171
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
172
|
+
def all_tags_list_on(context)
|
173
|
+
variable_name = "@all_#{context.to_s.singularize}_list"
|
174
|
+
if instance_variable_defined?(variable_name) && instance_variable_get(variable_name)
|
175
|
+
return instance_variable_get(variable_name)
|
176
|
+
end
|
153
177
|
|
154
|
-
|
155
|
-
variable_name = "@#{context.to_s.singularize}_list"
|
156
|
-
if instance_variable_get(variable_name)
|
157
|
-
instance_variable_get(variable_name)
|
158
|
-
elsif cached_tag_list_on(context) && ensure_included_cache_methods! && self.class.caching_tag_list_on?(context)
|
159
|
-
instance_variable_set(variable_name, ActsAsTaggableOn.default_parser.new(cached_tag_list_on(context)).parse)
|
160
|
-
else
|
161
|
-
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(tags_on(context).map(&:name)))
|
178
|
+
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(all_tags_on(context).map(&:name)).freeze)
|
162
179
|
end
|
163
|
-
end
|
164
180
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
181
|
+
##
|
182
|
+
# Returns all tags of a given context
|
183
|
+
def all_tags_on(context)
|
184
|
+
tagging_table_name = ActsAsTaggableOn::Tagging.table_name
|
169
185
|
|
170
|
-
|
171
|
-
|
172
|
-
return instance_variable_get(variable_name) if instance_variable_defined?(variable_name) && instance_variable_get(variable_name)
|
186
|
+
opts = ["#{tagging_table_name}.context = ?", context.to_s]
|
187
|
+
scope = base_tags.where(opts)
|
173
188
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
189
|
+
if ActsAsTaggableOn::Utils.using_postgresql?
|
190
|
+
group_columns = grouped_column_names_for(ActsAsTaggableOn::Tag)
|
191
|
+
scope.order(Arel.sql("max(#{tagging_table_name}.created_at)")).group(group_columns)
|
192
|
+
else
|
193
|
+
scope.group("#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}")
|
194
|
+
end.to_a
|
195
|
+
end
|
181
196
|
|
182
|
-
|
183
|
-
|
197
|
+
##
|
198
|
+
# Returns all tags that are not owned of a given context
|
199
|
+
def tags_on(context)
|
200
|
+
scope = base_tags.where([
|
201
|
+
"#{ActsAsTaggableOn::Tagging.table_name}.context = ? AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id IS NULL", context.to_s
|
202
|
+
])
|
203
|
+
# when preserving tag order, return tags in created order
|
204
|
+
# if we added the order to the association this would always apply
|
205
|
+
scope = scope.order("#{ActsAsTaggableOn::Tagging.table_name}.id") if self.class.preserve_tag_order?
|
206
|
+
scope
|
207
|
+
end
|
184
208
|
|
185
|
-
|
186
|
-
|
187
|
-
scope.order(Arel.sql("max(#{tagging_table_name}.created_at)")).group(group_columns)
|
188
|
-
else
|
189
|
-
scope.group("#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}")
|
190
|
-
end.to_a
|
191
|
-
end
|
209
|
+
def set_tag_list_on(context, new_list)
|
210
|
+
add_custom_context(context)
|
192
211
|
|
193
|
-
|
194
|
-
# Returns all tags that are not owned of a given context
|
195
|
-
def tags_on(context)
|
196
|
-
scope = base_tags.where(["#{ActsAsTaggableOn::Tagging.table_name}.context = ? AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id IS NULL", context.to_s])
|
197
|
-
# when preserving tag order, return tags in created order
|
198
|
-
# if we added the order to the association this would always apply
|
199
|
-
scope = scope.order("#{ActsAsTaggableOn::Tagging.table_name}.id") if self.class.preserve_tag_order?
|
200
|
-
scope
|
201
|
-
end
|
212
|
+
variable_name = "@#{context.to_s.singularize}_list"
|
202
213
|
|
203
|
-
|
204
|
-
add_custom_context(context)
|
214
|
+
parsed_new_list = ActsAsTaggableOn.default_parser.new(new_list).parse
|
205
215
|
|
206
|
-
|
216
|
+
instance_variable_set(variable_name, parsed_new_list)
|
217
|
+
end
|
207
218
|
|
208
|
-
|
219
|
+
def tagging_contexts
|
220
|
+
self.class.tag_types.map(&:to_s) + custom_contexts
|
221
|
+
end
|
209
222
|
|
210
|
-
|
211
|
-
|
223
|
+
def taggable_tenant
|
224
|
+
public_send(self.class.tenant_column) if self.class.tenant_column
|
225
|
+
end
|
212
226
|
|
213
|
-
|
214
|
-
|
215
|
-
|
227
|
+
def reload(*args)
|
228
|
+
self.class.tag_types.each do |context|
|
229
|
+
instance_variable_set("@#{context.to_s.singularize}_list", nil)
|
230
|
+
instance_variable_set("@all_#{context.to_s.singularize}_list", nil)
|
231
|
+
end
|
216
232
|
|
217
|
-
|
218
|
-
if self.class.tenant_column
|
219
|
-
public_send(self.class.tenant_column)
|
233
|
+
super(*args)
|
220
234
|
end
|
221
|
-
end
|
222
235
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
236
|
+
##
|
237
|
+
# Find existing tags or create non-existing tags
|
238
|
+
def load_tags(tag_list)
|
239
|
+
ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(tag_list)
|
227
240
|
end
|
228
241
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
##
|
233
|
-
# Find existing tags or create non-existing tags
|
234
|
-
def load_tags(tag_list)
|
235
|
-
ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(tag_list)
|
236
|
-
end
|
242
|
+
def save_tags
|
243
|
+
tagging_contexts.each do |context|
|
244
|
+
next unless tag_list_cache_set_on(context)
|
237
245
|
|
238
|
-
|
239
|
-
|
240
|
-
next unless tag_list_cache_set_on(context)
|
241
|
-
# List of currently assigned tag names
|
242
|
-
tag_list = tag_list_cache_on(context).uniq
|
246
|
+
# List of currently assigned tag names
|
247
|
+
tag_list = tag_list_cache_on(context).uniq
|
243
248
|
|
244
|
-
|
245
|
-
|
249
|
+
# Find existing tags or create non-existing tags:
|
250
|
+
tags = find_or_create_tags_from_list_with_context(tag_list, context)
|
246
251
|
|
247
|
-
|
248
|
-
|
252
|
+
# Tag objects for currently assigned tags
|
253
|
+
current_tags = tags_on(context)
|
249
254
|
|
250
|
-
|
251
|
-
|
252
|
-
|
255
|
+
# Tag maintenance based on whether preserving the created order of tags
|
256
|
+
old_tags = current_tags - tags
|
257
|
+
new_tags = tags - current_tags
|
258
|
+
if self.class.preserve_tag_order?
|
253
259
|
|
254
|
-
|
260
|
+
shared_tags = current_tags & tags
|
255
261
|
|
256
|
-
|
257
|
-
|
262
|
+
if shared_tags.any? && tags[0...shared_tags.size] != shared_tags
|
263
|
+
index = shared_tags.each_with_index do |_, i|
|
264
|
+
break i unless shared_tags[i] == tags[i]
|
265
|
+
end
|
258
266
|
|
259
|
-
|
260
|
-
|
261
|
-
|
267
|
+
# Update arrays of tag objects
|
268
|
+
old_tags |= current_tags[index...current_tags.size]
|
269
|
+
new_tags |= current_tags[index...current_tags.size] & shared_tags
|
262
270
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
271
|
+
# Order the array of tag objects to match the tag list
|
272
|
+
new_tags = tags.map do |t|
|
273
|
+
new_tags.find { |n| n.name.downcase == t.name.downcase }
|
274
|
+
end.compact
|
275
|
+
end
|
276
|
+
else
|
277
|
+
# Delete discarded tags and create new tags
|
267
278
|
end
|
268
|
-
else
|
269
|
-
# Delete discarded tags and create new tags
|
270
|
-
old_tags = current_tags - tags
|
271
|
-
new_tags = tags - current_tags
|
272
|
-
end
|
273
279
|
|
274
|
-
|
275
|
-
|
276
|
-
taggings.not_owned.by_context(context).where(tag_id: old_tags).destroy_all
|
277
|
-
end
|
280
|
+
# Destroy old taggings:
|
281
|
+
taggings.not_owned.by_context(context).where(tag_id: old_tags).destroy_all if old_tags.present?
|
278
282
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
283
|
+
# Create new taggings:
|
284
|
+
new_tags.each do |tag|
|
285
|
+
if taggable_tenant
|
286
|
+
taggings.create!(tag_id: tag.id, context: context.to_s, taggable: self, tenant: taggable_tenant)
|
287
|
+
else
|
288
|
+
taggings.create!(tag_id: tag.id, context: context.to_s, taggable: self)
|
289
|
+
end
|
285
290
|
end
|
286
291
|
end
|
287
|
-
end
|
288
292
|
|
289
|
-
|
290
|
-
|
293
|
+
true
|
294
|
+
end
|
291
295
|
|
292
|
-
|
296
|
+
private
|
293
297
|
|
294
|
-
|
295
|
-
|
296
|
-
|
298
|
+
def ensure_included_cache_methods!
|
299
|
+
self.class.columns
|
300
|
+
end
|
297
301
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
302
|
+
# Filters the tag lists from the attribute names.
|
303
|
+
def attributes_for_update(attribute_names)
|
304
|
+
tag_lists = tag_types.map { |tags_type| "#{tags_type.to_s.singularize}_list" }
|
305
|
+
super.delete_if { |attr| tag_lists.include? attr }
|
306
|
+
end
|
303
307
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
308
|
+
# Filters the tag lists from the attribute names.
|
309
|
+
def attributes_for_create(attribute_names)
|
310
|
+
tag_lists = tag_types.map { |tags_type| "#{tags_type.to_s.singularize}_list" }
|
311
|
+
super.delete_if { |attr| tag_lists.include? attr }
|
312
|
+
end
|
309
313
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
314
|
+
##
|
315
|
+
# Override this hook if you wish to subclass {ActsAsTaggableOn::Tag} --
|
316
|
+
# context is provided so that you may conditionally use a Tag subclass
|
317
|
+
# only for some contexts.
|
318
|
+
#
|
319
|
+
# @example Custom Tag class for one context
|
320
|
+
# class Company < ActiveRecord::Base
|
321
|
+
# acts_as_taggable_on :markets, :locations
|
322
|
+
#
|
323
|
+
# def find_or_create_tags_from_list_with_context(tag_list, context)
|
324
|
+
# if context.to_sym == :markets
|
325
|
+
# MarketTag.find_or_create_all_with_like_by_name(tag_list)
|
326
|
+
# else
|
327
|
+
# super
|
328
|
+
# end
|
329
|
+
# end
|
330
|
+
#
|
331
|
+
# @param [Array<String>] tag_list Tags to find or create
|
332
|
+
# @param [Symbol] context The tag context for the tag_list
|
333
|
+
def find_or_create_tags_from_list_with_context(tag_list, _context)
|
334
|
+
load_tags(tag_list)
|
335
|
+
end
|
331
336
|
end
|
332
337
|
end
|
333
338
|
end
|
334
|
-
|