Commit ecfd33c12f0d008d4b09b9dab486e3d0100239c3
1 parent
e18d5be5
Exists in
spb-stable
and in
2 other branches
Add acts-as-taggable-on-patch for gem version 2.4.1 and Rails 4.1.
Showing
1 changed file
with
130 additions
and
0 deletions
Show diff stats
... | ... | @@ -0,0 +1,130 @@ |
1 | +# This is a patch to address the issue in https://github.com/mbleigh/acts-as-taggable-on/issues/427 caused by | |
2 | +# https://github.com/rails/rails/commit/31a43ebc107fbd50e7e62567e5208a05909ec76c | |
3 | +# gem 'acts-as-taggable-on' has the fix included https://github.com/mbleigh/acts-as-taggable-on/commit/89bbed3864a9252276fb8dd7d535fce280454b90 | |
4 | +# but not in the currently used version of gem ('2.4.1') | |
5 | +# With replacement of 'acts-as-taggable-on' gem this file will become obsolete | |
6 | + | |
7 | +module ActsAsTaggableOn::Taggable | |
8 | + module Core | |
9 | + module ClassMethods | |
10 | + def tagged_with(tags, options = {}) | |
11 | + tag_list = ActsAsTaggableOn::TagList.from(tags) | |
12 | + empty_result = where("1 = 0") | |
13 | + | |
14 | + return empty_result if tag_list.empty? | |
15 | + | |
16 | + joins = [] | |
17 | + conditions = [] | |
18 | + having = [] | |
19 | + select_clause = [] | |
20 | + | |
21 | + context = options.delete(:on) | |
22 | + owned_by = options.delete(:owned_by) | |
23 | + alias_base_name = undecorated_table_name.gsub('.','_') | |
24 | + quote = ActsAsTaggableOn::Tag.using_postgresql? ? '"' : '' | |
25 | + | |
26 | + if options.delete(:exclude) | |
27 | + if options.delete(:wild) | |
28 | + tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{like_operator} ? ESCAPE '!'", "%#{escape_like(t)}%"]) }.join(" OR ") | |
29 | + else | |
30 | + tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{like_operator} ?", t]) }.join(" OR ") | |
31 | + end | |
32 | + | |
33 | + conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)})" | |
34 | + | |
35 | + if owned_by | |
36 | + joins << "JOIN #{ActsAsTaggableOn::Tagging.table_name}" + | |
37 | + " ON #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" + | |
38 | + " AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)}" + | |
39 | + " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = #{owned_by.id}" + | |
40 | + " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s, nil)}" | |
41 | + end | |
42 | + | |
43 | + elsif options.delete(:any) | |
44 | + # get tags, drop out if nothing returned (we need at least one) | |
45 | + tags = if options.delete(:wild) | |
46 | + ActsAsTaggableOn::Tag.named_like_any(tag_list) | |
47 | + else | |
48 | + ActsAsTaggableOn::Tag.named_any(tag_list) | |
49 | + end | |
50 | + | |
51 | + return empty_result unless tags.length > 0 | |
52 | + | |
53 | + # setup taggings alias so we can chain, ex: items_locations_taggings_awesome_cool_123 | |
54 | + # avoid ambiguous column name | |
55 | + taggings_context = context ? "_#{context}" : '' | |
56 | + | |
57 | + taggings_alias = adjust_taggings_alias( | |
58 | + "#{alias_base_name[0..4]}#{taggings_context[0..6]}_taggings_#{sha_prefix(tags.map(&:name).join('_'))}" | |
59 | + ) | |
60 | + | |
61 | + tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" + | |
62 | + " ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" + | |
63 | + " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}" | |
64 | + tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context | |
65 | + | |
66 | + # don't need to sanitize sql, map all ids and join with OR logic | |
67 | + conditions << tags.map { |t| "#{taggings_alias}.tag_id = #{t.id}" }.join(" OR ") | |
68 | + select_clause = "DISTINCT #{table_name}.*" unless context and tag_types.one? | |
69 | + | |
70 | + if owned_by | |
71 | + tagging_join << " AND " + | |
72 | + sanitize_sql([ | |
73 | + "#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?", | |
74 | + owned_by.id, | |
75 | + owned_by.class.base_class.to_s | |
76 | + ]) | |
77 | + end | |
78 | + | |
79 | + joins << tagging_join | |
80 | + else | |
81 | + tags = ActsAsTaggableOn::Tag.named_any(tag_list) | |
82 | + | |
83 | + return empty_result unless tags.length == tag_list.length | |
84 | + | |
85 | + tags.each do |tag| | |
86 | + taggings_alias = adjust_taggings_alias("#{alias_base_name[0..11]}_taggings_#{sha_prefix(tag.name)}") | |
87 | + tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" + | |
88 | + " ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" + | |
89 | + " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}" + | |
90 | + " AND #{taggings_alias}.tag_id = #{tag.id}" | |
91 | + | |
92 | + tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context | |
93 | + | |
94 | + if owned_by | |
95 | + tagging_join << " AND " + | |
96 | + sanitize_sql([ | |
97 | + "#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?", | |
98 | + owned_by.id, | |
99 | + owned_by.class.base_class.to_s | |
100 | + ]) | |
101 | + end | |
102 | + | |
103 | + joins << tagging_join | |
104 | + end | |
105 | + end | |
106 | + | |
107 | + taggings_alias, tags_alias = adjust_taggings_alias("#{alias_base_name}_taggings_group"), "#{alias_base_name}_tags_group" | |
108 | + | |
109 | + if options.delete(:match_all) | |
110 | + joins << "LEFT OUTER JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" + | |
111 | + " ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" + | |
112 | + " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}" | |
113 | + | |
114 | + | |
115 | + group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}" | |
116 | + group = group_columns | |
117 | + having = "COUNT(#{taggings_alias}.taggable_id) = #{tags.size}" | |
118 | + end | |
119 | + | |
120 | + select(select_clause) \ | |
121 | + .joins(joins.join(" ")) \ | |
122 | + .where(conditions.join(" AND ")) \ | |
123 | + .group(group) \ | |
124 | + .having(having) \ | |
125 | + .order(options[:order]) \ | |
126 | + .readonly(false) | |
127 | + end | |
128 | + end | |
129 | + end | |
130 | +end | ... | ... |