acts-as-taggable-on 7.0.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/spec.yml +76 -0
  3. data/Appraisals +13 -13
  4. data/CHANGELOG.md +27 -2
  5. data/Gemfile +1 -0
  6. data/README.md +32 -7
  7. data/acts-as-taggable-on.gemspec +2 -2
  8. data/db/migrate/1_acts_as_taggable_on_migration.rb +5 -8
  9. data/db/migrate/2_add_missing_unique_indices.rb +6 -8
  10. data/db/migrate/3_add_taggings_counter_cache_to_tags.rb +3 -6
  11. data/db/migrate/4_add_missing_taggable_index.rb +5 -7
  12. data/db/migrate/5_change_collation_for_tag_names.rb +4 -6
  13. data/db/migrate/6_add_missing_indexes_on_taggings.rb +15 -13
  14. data/db/migrate/7_add_tenant_to_taggings.rb +13 -0
  15. data/docker-compose.yml +15 -0
  16. data/gemfiles/activerecord_6.0.gemfile +5 -8
  17. data/gemfiles/activerecord_6.1.gemfile +3 -8
  18. data/gemfiles/{activerecord_5.2.gemfile → activerecord_7.0.gemfile} +6 -9
  19. data/lib/acts_as_taggable_on/default_parser.rb +8 -10
  20. data/lib/acts_as_taggable_on/engine.rb +2 -0
  21. data/lib/acts_as_taggable_on/generic_parser.rb +2 -0
  22. data/lib/acts_as_taggable_on/tag.rb +33 -27
  23. data/lib/acts_as_taggable_on/tag_list.rb +8 -11
  24. data/lib/acts_as_taggable_on/taggable/cache.rb +64 -62
  25. data/lib/acts_as_taggable_on/taggable/collection.rb +178 -142
  26. data/lib/acts_as_taggable_on/taggable/core.rb +250 -236
  27. data/lib/acts_as_taggable_on/taggable/ownership.rb +110 -98
  28. data/lib/acts_as_taggable_on/taggable/related.rb +60 -47
  29. data/lib/acts_as_taggable_on/taggable/tag_list_type.rb +6 -2
  30. data/lib/acts_as_taggable_on/taggable/tagged_with_query/all_tags_query.rb +110 -106
  31. data/lib/acts_as_taggable_on/taggable/tagged_with_query/any_tags_query.rb +57 -53
  32. data/lib/acts_as_taggable_on/taggable/tagged_with_query/exclude_tags_query.rb +63 -60
  33. data/lib/acts_as_taggable_on/taggable/tagged_with_query/query_base.rb +54 -46
  34. data/lib/acts_as_taggable_on/taggable/tagged_with_query.rb +14 -8
  35. data/lib/acts_as_taggable_on/taggable.rb +30 -12
  36. data/lib/acts_as_taggable_on/tagger.rb +9 -5
  37. data/lib/acts_as_taggable_on/tagging.rb +8 -4
  38. data/lib/acts_as_taggable_on/tags_helper.rb +3 -1
  39. data/lib/acts_as_taggable_on/utils.rb +4 -2
  40. data/lib/acts_as_taggable_on/version.rb +3 -1
  41. data/spec/acts_as_taggable_on/tag_spec.rb +16 -1
  42. data/spec/acts_as_taggable_on/taggable_spec.rb +6 -2
  43. data/spec/acts_as_taggable_on/tagging_spec.rb +26 -0
  44. data/spec/internal/app/models/taggable_model.rb +2 -0
  45. data/spec/internal/config/database.yml.sample +4 -8
  46. data/spec/internal/db/schema.rb +3 -0
  47. data/spec/support/database.rb +36 -26
  48. metadata +13 -22
  49. data/.travis.yml +0 -49
  50. data/UPGRADING.md +0 -8
  51. data/gemfiles/activerecord_5.0.gemfile +0 -21
  52. data/gemfiles/activerecord_5.1.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