acts-as-taggable-on 3.4.1 → 3.4.2

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 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.