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.
- checksums.yaml +4 -4
- data/.github/workflows/spec.yml +76 -0
- data/Appraisals +13 -13
- data/CHANGELOG.md +27 -2
- data/Gemfile +1 -0
- data/README.md +32 -7
- 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 +13 -0
- 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.2.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 +33 -27
- 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 +250 -236
- 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 +30 -12
- data/lib/acts_as_taggable_on/tagger.rb +9 -5
- data/lib/acts_as_taggable_on/tagging.rb +8 -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/acts_as_taggable_on/tag_spec.rb +16 -1
- data/spec/acts_as_taggable_on/taggable_spec.rb +6 -2
- data/spec/acts_as_taggable_on/tagging_spec.rb +26 -0
- data/spec/internal/app/models/taggable_model.rb +2 -0
- data/spec/internal/config/database.yml.sample +4 -8
- data/spec/internal/db/schema.rb +3 -0
- data/spec/support/database.rb +36 -26
- metadata +13 -22
- data/.travis.yml +0 -49
- data/UPGRADING.md +0 -8
- data/gemfiles/activerecord_5.0.gemfile +0 -21
- data/gemfiles/activerecord_5.1.gemfile +0 -21
@@ -1,136 +1,148 @@
|
|
1
|
-
|
2
|
-
module Ownership
|
3
|
-
def self.included(base)
|
4
|
-
base.extend ActsAsTaggableOn::Taggable::Ownership::ClassMethods
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module ActsAsTaggableOn
|
4
|
+
module Taggable
|
5
|
+
module Ownership
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ActsAsTaggableOn::Taggable::Ownership::ClassMethods
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
base.class_eval do
|
10
|
+
after_save :save_owned_tags
|
11
|
+
end
|
12
12
|
|
13
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
69
|
+
def owner_tag_list_on(owner, context)
|
70
|
+
add_custom_context(context)
|
68
71
|
|
69
|
-
|
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
|
-
|
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
|
-
|
86
|
-
|
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
|
-
|
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
|
-
|
96
|
-
|
82
|
+
cache[owner] = ActsAsTaggableOn.default_parser.new(new_list).parse
|
83
|
+
end
|
97
84
|
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
90
|
+
super(*args)
|
91
|
+
end
|
103
92
|
|
104
|
-
|
105
|
-
|
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
|
-
|
108
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
144
|
+
true
|
145
|
+
end
|
134
146
|
end
|
135
147
|
end
|
136
148
|
end
|
@@ -1,14 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
23
|
+
RUBY
|
24
|
+
end
|
21
25
|
end
|
22
|
-
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
60
|
+
private
|
50
61
|
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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,111 +1,115 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|