acts-as-taggable-on 3.4.1 → 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 281e3a40ea12a2d4bf7cd9a17548afaa79d38551
4
- data.tar.gz: 87e34ac29deab9211aea132e6f2189635d6918d5
3
+ metadata.gz: ee9d316a00b3742d99175e8535a48fc94bf32f7c
4
+ data.tar.gz: 0a2890ba670d7df947c9e3a271d81284abc9ef42
5
5
  SHA512:
6
- metadata.gz: 2168df4d62261fb9fbaacff107fb1311f9a9c8567f674b74e784dbd48a0e006825371cfa68de03595907974a1fc842383ca2ea90c2d48e51284a7398f492442a
7
- data.tar.gz: 4478cd0771d44535549f4516f9d087b94250e2087c8c75fe559752e1f033c8336167dcaede44b1223360d1e3821da8d515e5fb03398689ea3fb207dd9f15673b
6
+ metadata.gz: 3da825d4c0393da92b3eef9b8f94a140c7335ed6d810476bf3ba6ef7ccfa75409b9445713bebf8b13d4890be1b1c4aa3312197eaa57b9aedae713329c6203877
7
+ data.tar.gz: 0fb39c27169059d20607f33bc649655474a73003e5a210f4f5706ff73416f558cbb7ca4c94b9268c72a89501e3a6003ea9f9593a3678e09efecf953da3c0a4e6
@@ -4,7 +4,7 @@ Each change should fall into categories that would affect whether the release is
4
4
 
5
5
  As such, a _Feature_ would map to either major or minor. A _bug fix_ to a patch. And _misc_ is either minor or patch, the difference being kind of fuzzy for the purposes of history. Adding tests would be patch level.
6
6
 
7
- ### Master [changes](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.0...master)
7
+ ### Master [changes](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.2...master)
8
8
 
9
9
  * Breaking Changes
10
10
  * Features
@@ -12,6 +12,17 @@ As such, a _Feature_ would map to either major or minor. A _bug fix_ to a patch.
12
12
  * Performance
13
13
  * Misc
14
14
 
15
+ ### [3.4.2 / 2014-09-26](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.1...v3.4.2)
16
+
17
+ * Breaking Changes
18
+ * Features
19
+ * Fixes
20
+ * [@stiff fixed tagged_with :any in postgresql](https://github.com/mbleigh/acts-as-taggable-on/pull/570)
21
+ * [@jerefrer fixed encoding in mysql](https://github.com/mbleigh/acts-as-taggable-on/pull/588)
22
+ * [@markedmondson Ensure taggings context aliases are maintained when joining multiple taggables](https://github.com/mbleigh/acts-as-taggable-on/pull/589)
23
+ * Performance
24
+ * Misc
25
+
15
26
  ### [3.4.1 / 2014-09-01](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.0...v3.4.1)
16
27
  * Fixes
17
28
  * [@konukhov fix owned ordered taggable bug]((https://github.com/mbleigh/acts-as-taggable-on/pull/585)
data/Gemfile CHANGED
@@ -7,4 +7,5 @@ group :local_development do
7
7
  gem 'guard-rspec'
8
8
  gem 'appraisal'
9
9
  gem 'rake'
10
+ gem 'byebug' , platform: :mri_21
10
11
  end
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # ActsAsTaggableOn
2
+ [![Gem Version](https://badge.fury.io/rb/acts-as-taggable-on.svg)](http://badge.fury.io/rb/acts-as-taggable-on)
2
3
  [![Build Status](https://secure.travis-ci.org/mbleigh/acts-as-taggable-on.png)](http://travis-ci.org/mbleigh/acts-as-taggable-on)
3
4
  [![Code Climate](https://codeclimate.com/github/mbleigh/acts-as-taggable-on.png)](https://codeclimate.com/github/mbleigh/acts-as-taggable-on)
4
5
  [![Inline docs](http://inch-ci.org/github/mbleigh/acts-as-taggable-on.png)](http://inch-ci.org/github/mbleigh/acts-as-taggable-on)
@@ -31,7 +32,7 @@ For an up-to-date roadmap, see https://github.com/mbleigh/acts-as-taggable-on/is
31
32
  To use it, add it to your Gemfile:
32
33
 
33
34
  ```ruby
34
- gem 'acts-as-taggable-on'
35
+ gem 'acts-as-taggable-on', '~> 3.4'
35
36
  ```
36
37
 
37
38
  and bundle:
@@ -58,7 +58,8 @@ module ActsAsTaggableOn
58
58
 
59
59
  class Configuration
60
60
  attr_accessor :delimiter, :force_lowercase, :force_parameterize,
61
- :strict_case_match, :remove_unused_tags, :default_parser
61
+ :strict_case_match, :remove_unused_tags, :default_parser,
62
+ :tags_counter
62
63
 
63
64
  def initialize
64
65
  @delimiter = ','
@@ -66,6 +67,7 @@ module ActsAsTaggableOn
66
67
  @force_parameterize = false
67
68
  @strict_case_match = false
68
69
  @remove_unused_tags = false
70
+ @tags_counter = true
69
71
  @default_parser = DefaultParser
70
72
  end
71
73
 
@@ -32,17 +32,10 @@ module ActsAsTaggableOn
32
32
  end
33
33
 
34
34
  def self.named_any(list)
35
- if ActsAsTaggableOn.strict_case_match
36
- clause = list.map { |tag|
37
- sanitize_sql(["name = #{binary}?", as_8bit_ascii(tag)])
38
- }.join(' OR ')
39
- where(clause)
40
- else
41
- clause = list.map { |tag|
42
- sanitize_sql(['LOWER(name) = LOWER(?)', as_8bit_ascii(unicode_downcase(tag))])
43
- }.join(' OR ')
44
- where(clause)
45
- end
35
+ clause = list.map { |tag|
36
+ sanitize_sql_for_named_any(tag).force_encoding('BINARY')
37
+ }.join(' OR ')
38
+ where(clause)
46
39
  end
47
40
 
48
41
  def self.named_like(name)
@@ -135,6 +128,14 @@ module ActsAsTaggableOn
135
128
  string.to_s.mb_chars
136
129
  end
137
130
  end
131
+
132
+ def sanitize_sql_for_named_any(tag)
133
+ if ActsAsTaggableOn.strict_case_match
134
+ sanitize_sql(["name = #{binary}?", as_8bit_ascii(tag)])
135
+ else
136
+ sanitize_sql(['LOWER(name) = LOWER(?)', as_8bit_ascii(unicode_downcase(tag))])
137
+ end
138
+ end
138
139
  end
139
140
  end
140
141
  end
@@ -27,7 +27,7 @@ module ActsAsTaggableOn::Taggable
27
27
  dependent: :destroy,
28
28
  class_name: 'ActsAsTaggableOn::Tagging',
29
29
  order: taggings_order,
30
- conditions: ["#{ActsAsTaggableOn::Tagging.table_name}.context = (?)", tags_type],
30
+ conditions: {context: tags_type},
31
31
  include: :tag
32
32
 
33
33
  has_many_with_taggable_compatibility context_tags, through: context_taggings,
@@ -100,6 +100,7 @@ module ActsAsTaggableOn::Taggable
100
100
  context = options.delete(:on)
101
101
  owned_by = options.delete(:owned_by)
102
102
  alias_base_name = undecorated_table_name.gsub('.', '_')
103
+ # FIXME use ActiveRecord's connection quote_column_name
103
104
  quote = ActsAsTaggableOn::Utils.using_postgresql? ? '"' : ''
104
105
 
105
106
  if options.delete(:exclude)
@@ -117,7 +118,7 @@ module ActsAsTaggableOn::Taggable
117
118
  " AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)}" +
118
119
  " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = #{quote_value(owned_by.id, nil)}" +
119
120
  " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s, nil)}"
120
-
121
+
121
122
  joins << " AND " + sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
122
123
  joins << " AND " + sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
123
124
  end
@@ -130,7 +131,7 @@ module ActsAsTaggableOn::Taggable
130
131
  ActsAsTaggableOn::Tag.named_any(tag_list)
131
132
  end
132
133
 
133
- return empty_result unless tags.length > 0
134
+ return empty_result if tags.length == 0
134
135
 
135
136
  # setup taggings alias so we can chain, ex: items_locations_taggings_awesome_cool_123
136
137
  # avoid ambiguous column name
@@ -140,21 +141,22 @@ module ActsAsTaggableOn::Taggable
140
141
  "#{alias_base_name[0..4]}#{taggings_context[0..6]}_taggings_#{ActsAsTaggableOn::Utils.sha_prefix(tags.map(&:name).join('_'))}"
141
142
  )
142
143
 
143
- tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
144
- " ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
144
+ tagging_cond = "#{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
145
+ " WHERE #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
145
146
  " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}"
146
147
 
147
- tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
148
- tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
148
+ tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
149
+ tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
149
150
 
150
- tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context
151
+ tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context
151
152
 
152
153
  # don't need to sanitize sql, map all ids and join with OR logic
153
- conditions << tags.map { |t| "#{taggings_alias}.tag_id = #{quote_value(t.id, nil)}" }.join(' OR ')
154
+ tag_ids = tags.map { |t| quote_value(t.id, nil) }.join(', ')
155
+ tagging_cond << " AND #{taggings_alias}.tag_id in (#{tag_ids})"
154
156
  select_clause << " #{table_name}.*" unless context and tag_types.one?
155
157
 
156
158
  if owned_by
157
- tagging_join << ' AND ' +
159
+ tagging_cond << ' AND ' +
158
160
  sanitize_sql([
159
161
  "#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
160
162
  owned_by.id,
@@ -162,10 +164,9 @@ module ActsAsTaggableOn::Taggable
162
164
  ])
163
165
  end
164
166
 
165
- joins << tagging_join
166
- unless any == 'distinct' # Fix issue #544
167
- group = "#{table_name}.#{primary_key}"
168
- select_clause << group
167
+ conditions << "EXISTS (SELECT 1 FROM #{tagging_cond})"
168
+ if options.delete(:order_by_matching_tag_count)
169
+ order_by << "(SELECT count(*) FROM #{tagging_cond}) desc"
169
170
  end
170
171
  else
171
172
  tags = ActsAsTaggableOn::Tag.named_any(tag_list)
@@ -224,11 +225,11 @@ module ActsAsTaggableOn::Taggable
224
225
  query = self
225
226
  query = self.select(select_clause.join(',')) unless select_clause.empty?
226
227
  query.joins(joins.join(' '))
227
- .where(conditions.join(' AND '))
228
- .group(group)
229
- .having(having)
230
- .order(order_by.join(', '))
231
- .readonly(false)
228
+ .where(conditions.join(' AND '))
229
+ .group(group)
230
+ .having(having)
231
+ .order(order_by.join(', '))
232
+ .readonly(false)
232
233
  end
233
234
 
234
235
  def is_taggable?
@@ -11,7 +11,7 @@ module ActsAsTaggableOn
11
11
  :tagger_type,
12
12
  :tagger_id if defined?(ActiveModel::MassAssignmentSecurity)
13
13
 
14
- belongs_to :tag, class_name: 'ActsAsTaggableOn::Tag' , counter_cache: true
14
+ belongs_to :tag, class_name: 'ActsAsTaggableOn::Tag', counter_cache: ActsAsTaggableOn.tags_counter
15
15
  belongs_to :taggable, polymorphic: true
16
16
  belongs_to :tagger, polymorphic: true
17
17
 
@@ -32,7 +32,11 @@ module ActsAsTaggableOn
32
32
 
33
33
  def remove_unused_tags
34
34
  if ActsAsTaggableOn.remove_unused_tags
35
- tag.destroy if tag.reload.taggings_count.zero?
35
+ if ActsAsTaggableOn.tags_counter
36
+ tag.destroy if tag.reload.taggings_count.zero?
37
+ else
38
+ tag.destroy if tag.reload.taggings.count.zero?
39
+ end
36
40
  end
37
41
  end
38
42
  end
@@ -1,4 +1,4 @@
1
1
  module ActsAsTaggableOn
2
- VERSION = '3.4.1'
2
+ VERSION = '3.4.2'
3
3
  end
4
4
 
@@ -133,6 +133,22 @@ describe 'Acts As Taggable On' do
133
133
  expect(taggable1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to_not include(taggable1)
134
134
  end
135
135
 
136
+ it 'should ensure joins to multiple taggings maintain their contexts when aliasing' do
137
+ taggable1 = TaggableModel.create!(name: 'Taggable 1')
138
+
139
+ taggable1.offering_list = 'one'
140
+ taggable1.need_list = 'two'
141
+
142
+ taggable1.save
143
+
144
+ column = TaggableModel.connection.quote_column_name("context")
145
+ offer_alias = TaggableModel.connection.quote_table_name("taggings")
146
+ need_alias = TaggableModel.connection.quote_table_name("need_taggings_taggable_models_join")
147
+
148
+ expect(TaggableModel.joins(:offerings, :needs).to_sql).to include "#{offer_alias}.#{column}"
149
+ expect(TaggableModel.joins(:offerings, :needs).to_sql).to include "#{need_alias}.#{column}"
150
+ end
151
+
136
152
  end
137
153
 
138
154
  describe 'Tagging Contexts' do
@@ -46,6 +46,14 @@ describe ActsAsTaggableOn::Tag do
46
46
  end
47
47
  end
48
48
 
49
+ describe 'named any' do
50
+ context 'with some special characters combinations', if: using_mysql? do
51
+ it 'should not raise an invalid encoding exception' do
52
+ expect{ActsAsTaggableOn::Tag.named_any(["holä", "hol'ä"])}.not_to raise_error
53
+ end
54
+ end
55
+ end
56
+
49
57
  describe 'find or create by name' do
50
58
  before(:each) do
51
59
  @tag.name = 'awesome'
@@ -250,13 +258,19 @@ describe ActsAsTaggableOn::Tag do
250
258
  end
251
259
  end
252
260
 
253
- it 'should not change enconding' do
261
+ it 'should not change encoding' do
254
262
  name = "\u3042"
255
263
  original_encoding = name.encoding
256
264
  record = ActsAsTaggableOn::Tag.find_or_create_with_like_by_name(name)
257
265
  record.reload
258
266
  expect(record.name.encoding).to eq(original_encoding)
259
267
  end
268
+
269
+ context 'named any with some special characters combinations', if: using_mysql? do
270
+ it 'should not raise an invalid encoding exception' do
271
+ expect{ActsAsTaggableOn::Tag.named_any(["holä", "hol'ä"])}.not_to raise_error
272
+ end
273
+ end
260
274
  end
261
275
 
262
276
  describe 'name uniqeness validation' do
@@ -261,7 +261,7 @@ describe 'Taggable' do
261
261
  @taggable.tag_list = 'bob, charlie'
262
262
  @taggable.save
263
263
 
264
- expect(TaggableModel.group(:created_at).tagged_with(['bob', 'css'], :any => true).first).to eq(@taggable)
264
+ expect(TaggableModel.tagged_with(['bob', 'css'], :any => true).to_a).to eq([@taggable])
265
265
 
266
266
  bob = TaggableModel.create(:name => 'Bob', :tag_list => 'ruby, rails, css')
267
267
  frank = TaggableModel.create(:name => 'Frank', :tag_list => 'ruby, rails')
@@ -459,6 +459,7 @@ describe 'Taggable' do
459
459
 
460
460
  expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, any: true).to_a.sort_by { |o| o.id }).to eq([bob, frank, steve])
461
461
  expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, exclude: true).to_a).to eq([jim])
462
+ expect(TaggableModel.tagged_with('ji', wild: true, any: true).to_a).to eq([frank, jim])
462
463
  end
463
464
  end
464
465
 
@@ -1,3 +1,7 @@
1
+ begin
2
+ require 'byebug'
3
+ rescue LoadError
4
+ end
1
5
  $LOAD_PATH << '.' unless $LOAD_PATH.include?('.')
2
6
  $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
3
7
  require 'logger'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts-as-taggable-on
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.1
4
+ version: 3.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-09-01 00:00:00.000000000 Z
12
+ date: 2014-09-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -266,7 +266,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
266
266
  version: '0'
267
267
  requirements: []
268
268
  rubyforge_project:
269
- rubygems_version: 2.4.1
269
+ rubygems_version: 2.2.2
270
270
  signing_key:
271
271
  specification_version: 4
272
272
  summary: Advanced tagging for Rails.