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.
- checksums.yaml +4 -4
- data/.github/workflows/spec.yml +15 -34
- data/Appraisals +13 -13
- data/CHANGELOG.md +13 -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 -7
- 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,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
|