acts-as-taggable-on 8.1.0 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/spec.yml +15 -34
  3. data/Appraisals +13 -13
  4. data/CHANGELOG.md +13 -3
  5. data/README.md +6 -6
  6. data/acts-as-taggable-on.gemspec +2 -2
  7. data/db/migrate/1_acts_as_taggable_on_migration.rb +5 -7
  8. data/db/migrate/2_add_missing_unique_indices.rb +6 -8
  9. data/db/migrate/3_add_taggings_counter_cache_to_tags.rb +3 -6
  10. data/db/migrate/4_add_missing_taggable_index.rb +5 -7
  11. data/db/migrate/5_change_collation_for_tag_names.rb +4 -6
  12. data/db/migrate/6_add_missing_indexes_on_taggings.rb +15 -13
  13. data/db/migrate/7_add_tenant_to_taggings.rb +7 -10
  14. data/docker-compose.yml +15 -0
  15. data/gemfiles/activerecord_6.0.gemfile +5 -8
  16. data/gemfiles/activerecord_6.1.gemfile +3 -8
  17. data/gemfiles/{activerecord_5.0.gemfile → activerecord_7.0.gemfile} +6 -9
  18. data/lib/acts_as_taggable_on/default_parser.rb +8 -10
  19. data/lib/acts_as_taggable_on/engine.rb +2 -0
  20. data/lib/acts_as_taggable_on/generic_parser.rb +2 -0
  21. data/lib/acts_as_taggable_on/tag.rb +30 -30
  22. data/lib/acts_as_taggable_on/tag_list.rb +8 -11
  23. data/lib/acts_as_taggable_on/taggable/cache.rb +64 -62
  24. data/lib/acts_as_taggable_on/taggable/collection.rb +178 -142
  25. data/lib/acts_as_taggable_on/taggable/core.rb +248 -244
  26. data/lib/acts_as_taggable_on/taggable/ownership.rb +110 -98
  27. data/lib/acts_as_taggable_on/taggable/related.rb +60 -47
  28. data/lib/acts_as_taggable_on/taggable/tag_list_type.rb +6 -2
  29. data/lib/acts_as_taggable_on/taggable/tagged_with_query/all_tags_query.rb +110 -106
  30. data/lib/acts_as_taggable_on/taggable/tagged_with_query/any_tags_query.rb +57 -53
  31. data/lib/acts_as_taggable_on/taggable/tagged_with_query/exclude_tags_query.rb +63 -60
  32. data/lib/acts_as_taggable_on/taggable/tagged_with_query/query_base.rb +54 -46
  33. data/lib/acts_as_taggable_on/taggable/tagged_with_query.rb +14 -8
  34. data/lib/acts_as_taggable_on/taggable.rb +14 -14
  35. data/lib/acts_as_taggable_on/tagger.rb +9 -5
  36. data/lib/acts_as_taggable_on/tagging.rb +6 -4
  37. data/lib/acts_as_taggable_on/tags_helper.rb +3 -1
  38. data/lib/acts_as_taggable_on/utils.rb +4 -2
  39. data/lib/acts_as_taggable_on/version.rb +3 -1
  40. data/spec/support/database.rb +36 -26
  41. metadata +13 -14
  42. data/gemfiles/activerecord_5.1.gemfile +0 -21
  43. data/gemfiles/activerecord_5.2.gemfile +0 -21
@@ -1,136 +1,148 @@
1
- module ActsAsTaggableOn::Taggable
2
- module Ownership
3
- def self.included(base)
4
- base.extend ActsAsTaggableOn::Taggable::Ownership::ClassMethods
1
+ # frozen_string_literal: true
5
2
 
6
- base.class_eval do
7
- after_save :save_owned_tags
8
- end
3
+ module ActsAsTaggableOn
4
+ module Taggable
5
+ module Ownership
6
+ def self.included(base)
7
+ base.extend ActsAsTaggableOn::Taggable::Ownership::ClassMethods
9
8
 
10
- base.initialize_acts_as_taggable_on_ownership
11
- end
9
+ base.class_eval do
10
+ after_save :save_owned_tags
11
+ end
12
12
 
13
- module ClassMethods
14
- def acts_as_taggable_on(*args)
15
- initialize_acts_as_taggable_on_ownership
16
- super(*args)
13
+ base.initialize_acts_as_taggable_on_ownership
17
14
  end
18
15
 
19
- def initialize_acts_as_taggable_on_ownership
20
- tag_types.map(&:to_s).each do |tag_type|
21
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
16
+ module ClassMethods
17
+ def acts_as_taggable_on(*args)
18
+ initialize_acts_as_taggable_on_ownership
19
+ super(*args)
20
+ end
21
+
22
+ def initialize_acts_as_taggable_on_ownership
23
+ tag_types.map(&:to_s).each do |tag_type|
24
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
22
25
  def #{tag_type}_from(owner)
23
26
  owner_tag_list_on(owner, '#{tag_type}')
24
27
  end
25
- RUBY
28
+ RUBY
29
+ end
30
+ end
31
+ end
32
+
33
+ def owner_tags(owner)
34
+ scope = if owner.nil?
35
+ base_tags
36
+ else
37
+ base_tags.where(
38
+ ActsAsTaggableOn::Tagging.table_name.to_s => {
39
+ tagger_id: owner.id,
40
+ tagger_type: owner.class.base_class.to_s
41
+ }
42
+ )
43
+ end
44
+
45
+ # when preserving tag order, return tags in created order
46
+ # if we added the order to the association this would always apply
47
+ if self.class.preserve_tag_order?
48
+ scope.order("#{ActsAsTaggableOn::Tagging.table_name}.id")
49
+ else
50
+ scope
26
51
  end
27
52
  end
28
- end
29
53
 
30
- def owner_tags(owner)
31
- if owner.nil?
32
- scope = base_tags
33
- else
34
- scope = base_tags.where(
35
- "#{ActsAsTaggableOn::Tagging.table_name}" => {
36
- tagger_id: owner.id,
37
- tagger_type: owner.class.base_class.to_s
54
+ def owner_tags_on(owner, context)
55
+ owner_tags(owner).where(
56
+ ActsAsTaggableOn::Tagging.table_name.to_s => {
57
+ context: context
38
58
  }
39
59
  )
40
60
  end
41
61
 
42
- # when preserving tag order, return tags in created order
43
- # if we added the order to the association this would always apply
44
- if self.class.preserve_tag_order?
45
- scope.order("#{ActsAsTaggableOn::Tagging.table_name}.id")
46
- else
47
- scope
62
+ def cached_owned_tag_list_on(context)
63
+ variable_name = "@owned_#{context}_list"
64
+ (instance_variable_defined?(variable_name) && instance_variable_get(variable_name)) || instance_variable_set(
65
+ variable_name, {}
66
+ )
48
67
  end
49
- end
50
-
51
- def owner_tags_on(owner, context)
52
- owner_tags(owner).where(
53
- "#{ActsAsTaggableOn::Tagging.table_name}" => {
54
- context: context
55
- }
56
- )
57
- end
58
-
59
- def cached_owned_tag_list_on(context)
60
- variable_name = "@owned_#{context}_list"
61
- (instance_variable_defined?(variable_name) && instance_variable_get(variable_name)) || instance_variable_set(variable_name, {})
62
- end
63
-
64
- def owner_tag_list_on(owner, context)
65
- add_custom_context(context)
66
68
 
67
- cache = cached_owned_tag_list_on(context)
69
+ def owner_tag_list_on(owner, context)
70
+ add_custom_context(context)
68
71
 
69
- cache[owner] ||= ActsAsTaggableOn::TagList.new(*owner_tags_on(owner, context).map(&:name))
70
- end
71
-
72
- def set_owner_tag_list_on(owner, context, new_list)
73
- add_custom_context(context)
74
-
75
- cache = cached_owned_tag_list_on(context)
76
-
77
- cache[owner] = ActsAsTaggableOn.default_parser.new(new_list).parse
78
- end
72
+ cache = cached_owned_tag_list_on(context)
79
73
 
80
- def reload(*args)
81
- self.class.tag_types.each do |context|
82
- instance_variable_set("@owned_#{context}_list", nil)
74
+ cache[owner] ||= ActsAsTaggableOn::TagList.new(*owner_tags_on(owner, context).map(&:name))
83
75
  end
84
76
 
85
- super(*args)
86
- end
87
-
88
- def save_owned_tags
89
- tagging_contexts.each do |context|
90
- cached_owned_tag_list_on(context).each do |owner, tag_list|
77
+ def set_owner_tag_list_on(owner, context, new_list)
78
+ add_custom_context(context)
91
79
 
92
- # Find existing tags or create non-existing tags:
93
- tags = find_or_create_tags_from_list_with_context(tag_list.uniq, context)
80
+ cache = cached_owned_tag_list_on(context)
94
81
 
95
- # Tag objects for owned tags
96
- owned_tags = owner_tags_on(owner, context).to_a
82
+ cache[owner] = ActsAsTaggableOn.default_parser.new(new_list).parse
83
+ end
97
84
 
98
- # Tag maintenance based on whether preserving the created order of tags
99
- if self.class.preserve_tag_order?
100
- old_tags, new_tags = owned_tags - tags, tags - owned_tags
85
+ def reload(*args)
86
+ self.class.tag_types.each do |context|
87
+ instance_variable_set("@owned_#{context}_list", nil)
88
+ end
101
89
 
102
- shared_tags = owned_tags & tags
90
+ super(*args)
91
+ end
103
92
 
104
- if shared_tags.any? && tags[0...shared_tags.size] != shared_tags
105
- index = shared_tags.each_with_index { |_, i| break i unless shared_tags[i] == tags[i] }
93
+ def save_owned_tags
94
+ tagging_contexts.each do |context|
95
+ cached_owned_tag_list_on(context).each do |owner, tag_list|
96
+ # Find existing tags or create non-existing tags:
97
+ tags = find_or_create_tags_from_list_with_context(tag_list.uniq, context)
106
98
 
107
- # Update arrays of tag objects
108
- old_tags |= owned_tags.from(index)
109
- new_tags |= owned_tags.from(index) & shared_tags
99
+ # Tag objects for owned tags
100
+ owned_tags = owner_tags_on(owner, context).to_a
110
101
 
111
- # Order the array of tag objects to match the tag list
112
- new_tags = tags.map { |t| new_tags.find { |n| n.name.downcase == t.name.downcase } }.compact
113
- end
114
- else
115
- # Delete discarded tags and create new tags
102
+ # Tag maintenance based on whether preserving the created order of tags
116
103
  old_tags = owned_tags - tags
117
104
  new_tags = tags - owned_tags
118
- end
105
+ if self.class.preserve_tag_order?
106
+
107
+ shared_tags = owned_tags & tags
108
+
109
+ if shared_tags.any? && tags[0...shared_tags.size] != shared_tags
110
+ index = shared_tags.each_with_index do |_, i|
111
+ break i unless shared_tags[i] == tags[i]
112
+ end
113
+
114
+ # Update arrays of tag objects
115
+ old_tags |= owned_tags.from(index)
116
+ new_tags |= owned_tags.from(index) & shared_tags
117
+
118
+ # Order the array of tag objects to match the tag list
119
+ new_tags = tags.map do |t|
120
+ new_tags.find do |n|
121
+ n.name.downcase == t.name.downcase
122
+ end
123
+ end.compact
124
+ end
125
+ else
126
+ # Delete discarded tags and create new tags
127
+ end
119
128
 
120
- # Find all taggings that belong to the taggable (self), are owned by the owner,
121
- # have the correct context, and are removed from the list.
122
- ActsAsTaggableOn::Tagging.where(taggable_id: id, taggable_type: self.class.base_class.to_s,
123
- tagger_type: owner.class.base_class.to_s, tagger_id: owner.id,
124
- tag_id: old_tags, context: context).destroy_all if old_tags.present?
129
+ # Find all taggings that belong to the taggable (self), are owned by the owner,
130
+ # have the correct context, and are removed from the list.
131
+ if old_tags.present?
132
+ ActsAsTaggableOn::Tagging.where(taggable_id: id, taggable_type: self.class.base_class.to_s,
133
+ tagger_type: owner.class.base_class.to_s, tagger_id: owner.id,
134
+ tag_id: old_tags, context: context).destroy_all
135
+ end
125
136
 
126
- # Create new taggings:
127
- new_tags.each do |tag|
128
- taggings.create!(tag_id: tag.id, context: context.to_s, tagger: owner, taggable: self)
137
+ # Create new taggings:
138
+ new_tags.each do |tag|
139
+ taggings.create!(tag_id: tag.id, context: context.to_s, tagger: owner, taggable: self)
140
+ end
129
141
  end
130
142
  end
131
- end
132
143
 
133
- true
144
+ true
145
+ end
134
146
  end
135
147
  end
136
148
  end
@@ -1,14 +1,17 @@
1
- module ActsAsTaggableOn::Taggable
2
- module Related
3
- def self.included(base)
4
- base.extend ActsAsTaggableOn::Taggable::Related::ClassMethods
5
- base.initialize_acts_as_taggable_on_related
6
- end
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOn
4
+ module Taggable
5
+ module Related
6
+ def self.included(base)
7
+ base.extend ActsAsTaggableOn::Taggable::Related::ClassMethods
8
+ base.initialize_acts_as_taggable_on_related
9
+ end
7
10
 
8
- module ClassMethods
9
- def initialize_acts_as_taggable_on_related
10
- tag_types.map(&:to_s).each do |tag_type|
11
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
11
+ module ClassMethods
12
+ def initialize_acts_as_taggable_on_related
13
+ tag_types.map(&:to_s).each do |tag_type|
14
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
12
15
  def find_related_#{tag_type}(options = {})
13
16
  related_tags_for('#{tag_type}', self.class, options)
14
17
  end
@@ -17,55 +20,65 @@ module ActsAsTaggableOn::Taggable
17
20
  def find_related_#{tag_type}_for(klass, options = {})
18
21
  related_tags_for('#{tag_type}', klass, options)
19
22
  end
20
- RUBY
23
+ RUBY
24
+ end
21
25
  end
22
- end
23
26
 
24
- def acts_as_taggable_on(*args)
25
- super(*args)
26
- initialize_acts_as_taggable_on_related
27
+ def acts_as_taggable_on(*args)
28
+ super(*args)
29
+ initialize_acts_as_taggable_on_related
30
+ end
27
31
  end
28
- end
29
32
 
30
- def find_matching_contexts(search_context, result_context, options = {})
31
- matching_contexts_for(search_context.to_s, result_context.to_s, self.class, options)
32
- end
33
+ def find_matching_contexts(search_context, result_context, options = {})
34
+ matching_contexts_for(search_context.to_s, result_context.to_s, self.class, options)
35
+ end
33
36
 
34
- def find_matching_contexts_for(klass, search_context, result_context, options = {})
35
- matching_contexts_for(search_context.to_s, result_context.to_s, klass, options)
36
- end
37
+ def find_matching_contexts_for(klass, search_context, result_context, options = {})
38
+ matching_contexts_for(search_context.to_s, result_context.to_s, klass, options)
39
+ end
37
40
 
38
- def matching_contexts_for(search_context, result_context, klass, options = {})
39
- tags_to_find = tags_on(search_context).map { |t| t.name }
40
- related_where(klass, ["#{exclude_self(klass, id)} #{klass.table_name}.#{klass.primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.base_class}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?) AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_to_find, result_context])
41
- end
41
+ def matching_contexts_for(search_context, result_context, klass, _options = {})
42
+ tags_to_find = tags_on(search_context).map(&:name)
43
+ related_where(klass,
44
+ [
45
+ "#{exclude_self(klass,
46
+ id)} #{klass.table_name}.#{klass.primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.base_class}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?) AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_to_find, result_context
47
+ ])
48
+ end
42
49
 
43
- def related_tags_for(context, klass, options = {})
44
- tags_to_ignore = Array.wrap(options[:ignore]).map(&:to_s) || []
45
- tags_to_find = tags_on(context).map { |t| t.name }.reject { |t| tags_to_ignore.include? t }
46
- related_where(klass, ["#{exclude_self(klass, id)} #{klass.table_name}.#{klass.primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.base_class}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?) AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_to_find, context])
47
- end
50
+ def related_tags_for(context, klass, options = {})
51
+ tags_to_ignore = Array.wrap(options[:ignore]).map(&:to_s) || []
52
+ tags_to_find = tags_on(context).map(&:name).reject { |t| tags_to_ignore.include? t }
53
+ related_where(klass,
54
+ [
55
+ "#{exclude_self(klass,
56
+ id)} #{klass.table_name}.#{klass.primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.base_class}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?) AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_to_find, context
57
+ ])
58
+ end
48
59
 
49
- private
60
+ private
50
61
 
51
- def exclude_self(klass, id)
52
- "#{klass.arel_table[klass.primary_key].not_eq(id).to_sql} AND" if [self.class.base_class, self.class].include? klass
53
- end
62
+ def exclude_self(klass, id)
63
+ "#{klass.arel_table[klass.primary_key].not_eq(id).to_sql} AND" if [self.class.base_class,
64
+ self.class].include? klass
65
+ end
54
66
 
55
- def group_columns(klass)
56
- if ActsAsTaggableOn::Utils.using_postgresql?
57
- grouped_column_names_for(klass)
58
- else
59
- "#{klass.table_name}.#{klass.primary_key}"
67
+ def group_columns(klass)
68
+ if ActsAsTaggableOn::Utils.using_postgresql?
69
+ grouped_column_names_for(klass)
70
+ else
71
+ "#{klass.table_name}.#{klass.primary_key}"
72
+ end
60
73
  end
61
- end
62
74
 
63
- def related_where(klass, conditions)
64
- klass.select("#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}) AS count")
65
- .from("#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}")
66
- .group(group_columns(klass))
67
- .order('count DESC')
68
- .where(conditions)
75
+ def related_where(klass, conditions)
76
+ klass.select("#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}) AS count")
77
+ .from("#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}")
78
+ .group(group_columns(klass))
79
+ .order('count DESC')
80
+ .where(conditions)
81
+ end
69
82
  end
70
83
  end
71
84
  end
@@ -1,4 +1,8 @@
1
- module ActsAsTaggableOn::Taggable
2
- class TagListType < ActiveModel::Type::Value
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOn
4
+ module Taggable
5
+ class TagListType < ActiveModel::Type::Value
6
+ end
3
7
  end
4
8
  end
@@ -1,111 +1,115 @@
1
- module ActsAsTaggableOn::Taggable::TaggedWithQuery
2
- class AllTagsQuery < QueryBase
3
- def build
4
- taggable_model.joins(each_tag_in_list)
5
- .group(by_taggable)
6
- .having(tags_that_matches_count)
7
- .order(order_conditions)
8
- .readonly(false)
9
- end
10
-
11
- private
12
-
13
- def each_tag_in_list
14
- arel_join = taggable_arel_table
15
-
16
- tag_list.each do |tag|
17
- tagging_alias = tagging_arel_table.alias(tagging_alias(tag))
18
- arel_join = arel_join
19
- .join(tagging_alias)
20
- .on(on_conditions(tag, tagging_alias))
21
- end
22
-
23
- if options[:match_all].present?
24
- arel_join = arel_join
25
- .join(tagging_arel_table, Arel::Nodes::OuterJoin)
26
- .on(
27
- match_all_on_conditions
28
- )
29
- end
30
-
31
- return arel_join.join_sources
32
- end
33
-
34
- def on_conditions(tag, tagging_alias)
35
- on_condition = tagging_alias[:taggable_id].eq(taggable_arel_table[taggable_model.primary_key])
36
- .and(tagging_alias[:taggable_type].eq(taggable_model.base_class.name))
37
- .and(
38
- tagging_alias[:tag_id].in(
39
- tag_arel_table.project(tag_arel_table[:id]).where(tag_match_type(tag))
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOn
4
+ module Taggable
5
+ module TaggedWithQuery
6
+ class AllTagsQuery < QueryBase
7
+ def build
8
+ taggable_model.joins(each_tag_in_list)
9
+ .group(by_taggable)
10
+ .having(tags_that_matches_count)
11
+ .order(order_conditions)
12
+ .readonly(false)
13
+ end
14
+
15
+ private
16
+
17
+ def each_tag_in_list
18
+ arel_join = taggable_arel_table
19
+
20
+ tag_list.each do |tag|
21
+ tagging_alias = tagging_arel_table.alias(tagging_alias(tag))
22
+ arel_join = arel_join
23
+ .join(tagging_alias)
24
+ .on(on_conditions(tag, tagging_alias))
25
+ end
26
+
27
+ if options[:match_all].present?
28
+ arel_join = arel_join
29
+ .join(tagging_arel_table, Arel::Nodes::OuterJoin)
30
+ .on(
31
+ match_all_on_conditions
32
+ )
33
+ end
34
+
35
+ arel_join.join_sources
36
+ end
37
+
38
+ def on_conditions(tag, tagging_alias)
39
+ on_condition = tagging_alias[:taggable_id].eq(taggable_arel_table[taggable_model.primary_key])
40
+ .and(tagging_alias[:taggable_type].eq(taggable_model.base_class.name))
41
+ .and(
42
+ tagging_alias[:tag_id].in(
43
+ tag_arel_table.project(tag_arel_table[:id]).where(tag_match_type(tag))
44
+ )
45
+ )
46
+
47
+ if options[:start_at].present?
48
+ on_condition = on_condition.and(tagging_alias[:created_at].gteq(options[:start_at]))
49
+ end
50
+
51
+ if options[:end_at].present?
52
+ on_condition = on_condition.and(tagging_alias[:created_at].lteq(options[:end_at]))
53
+ end
54
+
55
+ on_condition = on_condition.and(tagging_alias[:context].eq(options[:on])) if options[:on].present?
56
+
57
+ if (owner = options[:owned_by]).present?
58
+ on_condition = on_condition.and(tagging_alias[:tagger_id].eq(owner.id))
59
+ .and(tagging_alias[:tagger_type].eq(owner.class.base_class.to_s))
60
+ end
61
+
62
+ on_condition
63
+ end
64
+
65
+ def match_all_on_conditions
66
+ on_condition = tagging_arel_table[:taggable_id].eq(taggable_arel_table[taggable_model.primary_key])
67
+ .and(tagging_arel_table[:taggable_type].eq(taggable_model.base_class.name))
68
+
69
+ if options[:start_at].present?
70
+ on_condition = on_condition.and(tagging_arel_table[:created_at].gteq(options[:start_at]))
71
+ end
72
+
73
+ if options[:end_at].present?
74
+ on_condition = on_condition.and(tagging_arel_table[:created_at].lteq(options[:end_at]))
75
+ end
76
+
77
+ on_condition = on_condition.and(tagging_arel_table[:context].eq(options[:on])) if options[:on].present?
78
+
79
+ on_condition
80
+ end
81
+
82
+ def by_taggable
83
+ return [] if options[:match_all].blank?
84
+
85
+ taggable_arel_table[taggable_model.primary_key]
86
+ end
87
+
88
+ def tags_that_matches_count
89
+ return [] if options[:match_all].blank?
90
+
91
+ taggable_model.find_by_sql(tag_arel_table.project(Arel.star.count).where(tags_match_type).to_sql)
92
+
93
+ tagging_arel_table[:taggable_id].count.eq(
94
+ tag_arel_table.project(Arel.star.count).where(tags_match_type)
40
95
  )
41
- )
42
-
43
- if options[:start_at].present?
44
- on_condition = on_condition.and(tagging_alias[:created_at].gteq(options[:start_at]))
45
- end
46
-
47
- if options[:end_at].present?
48
- on_condition = on_condition.and(tagging_alias[:created_at].lteq(options[:end_at]))
49
- end
50
-
51
- if options[:on].present?
52
- on_condition = on_condition.and(tagging_alias[:context].eq(options[:on]))
53
- end
54
-
55
- if (owner = options[:owned_by]).present?
56
- on_condition = on_condition.and(tagging_alias[:tagger_id].eq(owner.id))
57
- .and(tagging_alias[:tagger_type].eq(owner.class.base_class.to_s))
58
- end
59
-
60
- on_condition
61
- end
62
-
63
- def match_all_on_conditions
64
- on_condition = tagging_arel_table[:taggable_id].eq(taggable_arel_table[taggable_model.primary_key])
65
- .and(tagging_arel_table[:taggable_type].eq(taggable_model.base_class.name))
66
-
67
- if options[:start_at].present?
68
- on_condition = on_condition.and(tagging_arel_table[:created_at].gteq(options[:start_at]))
69
- end
70
-
71
- if options[:end_at].present?
72
- on_condition = on_condition.and(tagging_arel_table[:created_at].lteq(options[:end_at]))
96
+ end
97
+
98
+ def order_conditions
99
+ order_by = []
100
+ if options[:order_by_matching_tag_count].present? && options[:match_all].blank?
101
+ order_by << tagging_arel_table.project(tagging_arel_table[Arel.star].count.as('taggings_count')).order('taggings_count DESC').to_sql
102
+ end
103
+
104
+ order_by << options[:order] if options[:order].present?
105
+ order_by.join(', ')
106
+ end
107
+
108
+ def tagging_alias(tag)
109
+ alias_base_name = taggable_model.base_class.name.downcase
110
+ adjust_taggings_alias("#{alias_base_name[0..11]}_taggings_#{ActsAsTaggableOn::Utils.sha_prefix(tag)}")
111
+ end
73
112
  end
74
-
75
- if options[:on].present?
76
- on_condition = on_condition.and(tagging_arel_table[:context].eq(options[:on]))
77
- end
78
-
79
- on_condition
80
- end
81
-
82
- def by_taggable
83
- return [] unless options[:match_all].present?
84
-
85
- taggable_arel_table[taggable_model.primary_key]
86
- end
87
-
88
- def tags_that_matches_count
89
- return [] unless options[:match_all].present?
90
-
91
- taggable_model.find_by_sql(tag_arel_table.project(Arel.star.count).where(tags_match_type).to_sql)
92
-
93
- tagging_arel_table[:taggable_id].count.eq(
94
- tag_arel_table.project(Arel.star.count).where(tags_match_type)
95
- )
96
- end
97
-
98
- def order_conditions
99
- order_by = []
100
- order_by << tagging_arel_table.project(tagging_arel_table[Arel.star].count.as('taggings_count')).order('taggings_count DESC').to_sql if options[:order_by_matching_tag_count].present? && options[:match_all].blank?
101
-
102
- order_by << options[:order] if options[:order].present?
103
- order_by.join(', ')
104
- end
105
-
106
- def tagging_alias(tag)
107
- alias_base_name = taggable_model.base_class.name.downcase
108
- adjust_taggings_alias("#{alias_base_name[0..11]}_taggings_#{ActsAsTaggableOn::Utils.sha_prefix(tag)}")
109
113
  end
110
114
  end
111
115
  end