acts-as-taggable-on 3.2.1 → 4.0.0

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +25 -12
  4. data/Appraisals +9 -12
  5. data/CHANGELOG.md +120 -10
  6. data/Gemfile +2 -1
  7. data/README.md +163 -27
  8. data/Rakefile +2 -0
  9. data/UPGRADING.md +2 -7
  10. data/acts-as-taggable-on.gemspec +4 -6
  11. data/db/migrate/2_add_missing_unique_indices.rb +3 -2
  12. data/db/migrate/4_add_missing_taggable_index.rb +9 -0
  13. data/db/migrate/5_change_collation_for_tag_names.rb +9 -0
  14. data/db/migrate/6_add_missing_indexes.rb +12 -0
  15. data/gemfiles/activerecord_4.0.gemfile +3 -2
  16. data/gemfiles/activerecord_4.1.gemfile +3 -2
  17. data/gemfiles/{activerecord_3.2.gemfile → activerecord_4.2.gemfile} +2 -2
  18. data/gemfiles/{activerecord_edge.gemfile → activerecord_5.0.gemfile} +2 -3
  19. data/lib/acts-as-taggable-on.rb +79 -23
  20. data/lib/acts_as_taggable_on/default_parser.rb +79 -0
  21. data/lib/acts_as_taggable_on/engine.rb +0 -1
  22. data/lib/acts_as_taggable_on/generic_parser.rb +19 -0
  23. data/lib/acts_as_taggable_on/tag.rb +25 -15
  24. data/lib/acts_as_taggable_on/tag_list.rb +11 -81
  25. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/cache.rb +6 -1
  26. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/collection.rb +9 -4
  27. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/core.rb +103 -61
  28. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/ownership.rb +5 -5
  29. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/related.rb +7 -7
  30. data/lib/acts_as_taggable_on/taggable.rb +9 -10
  31. data/lib/acts_as_taggable_on/tagger.rb +12 -11
  32. data/lib/acts_as_taggable_on/tagging.rb +14 -14
  33. data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
  34. data/lib/acts_as_taggable_on/utils.rb +25 -50
  35. data/lib/acts_as_taggable_on/version.rb +1 -1
  36. data/lib/tasks/tags_collate_utf8.rake +21 -0
  37. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +27 -2
  38. data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +2 -1
  39. data/spec/acts_as_taggable_on/caching_spec.rb +29 -0
  40. data/spec/acts_as_taggable_on/default_parser_spec.rb +47 -0
  41. data/spec/acts_as_taggable_on/generic_parser_spec.rb +14 -0
  42. data/spec/acts_as_taggable_on/related_spec.rb +10 -0
  43. data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +1 -0
  44. data/spec/acts_as_taggable_on/tag_list_spec.rb +48 -30
  45. data/spec/acts_as_taggable_on/tag_spec.rb +86 -39
  46. data/spec/acts_as_taggable_on/taggable/dirty_spec.rb +127 -0
  47. data/spec/acts_as_taggable_on/taggable_spec.rb +103 -168
  48. data/spec/acts_as_taggable_on/tagger_spec.rb +14 -1
  49. data/spec/acts_as_taggable_on/tagging_spec.rb +91 -1
  50. data/spec/acts_as_taggable_on/tags_helper_spec.rb +1 -0
  51. data/spec/acts_as_taggable_on/utils_spec.rb +13 -11
  52. data/spec/internal/app/models/cached_model_with_array.rb +1 -1
  53. data/spec/internal/app/models/models.rb +2 -2
  54. data/spec/internal/db/schema.rb +9 -5
  55. data/spec/spec_helper.rb +4 -1
  56. data/spec/support/0-helpers.rb +32 -0
  57. data/spec/support/database.rb +1 -7
  58. data/spec/support/database_cleaner.rb +4 -0
  59. metadata +34 -71
  60. data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +0 -35
  61. data/spec/bm.rb +0 -52
  62. data/spec/schema.rb +0 -82
  63. /data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/dirty.rb +0 -0
@@ -2,14 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 4.0"
6
- gem "actionpack", "~> 4.0"
5
+ gem "activerecord", "~> 4.0.0"
6
+ gem "mysql2", "~> 0.3.21"
7
7
 
8
8
  group :local_development do
9
9
  gem "guard"
10
10
  gem "guard-rspec"
11
11
  gem "appraisal"
12
12
  gem "rake"
13
+ gem "byebug", :platforms => [:mri_21, :mri_22, :mri_23]
13
14
  end
14
15
 
15
16
  gemspec :path => "../"
@@ -2,14 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 4.1"
6
- gem "actionpack", "~> 4.1"
5
+ gem "activerecord", "~> 4.1.0"
6
+ gem "mysql2", "~> 0.3.21"
7
7
 
8
8
  group :local_development do
9
9
  gem "guard"
10
10
  gem "guard-rspec"
11
11
  gem "appraisal"
12
12
  gem "rake"
13
+ gem "byebug", :platforms => [:mri_21, :mri_22, :mri_23]
13
14
  end
14
15
 
15
16
  gemspec :path => "../"
@@ -2,14 +2,14 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 3.2"
6
- gem "actionpack", "~> 3.2"
5
+ gem "activerecord", "~> 4.2.0"
7
6
 
8
7
  group :local_development do
9
8
  gem "guard"
10
9
  gem "guard-rspec"
11
10
  gem "appraisal"
12
11
  gem "rake"
12
+ gem "byebug", :platforms => [:mri_21, :mri_22, :mri_23]
13
13
  end
14
14
 
15
15
  gemspec :path => "../"
@@ -2,15 +2,14 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", :github => "rails/rails"
6
- gem "actionpack", :github => "rails/rails"
7
- gem "arel", :github => "rails/arel"
5
+ gem "activerecord", "~> 5.0.0"
8
6
 
9
7
  group :local_development do
10
8
  gem "guard"
11
9
  gem "guard-rspec"
12
10
  gem "appraisal"
13
11
  gem "rake"
12
+ gem "byebug", :platforms => [:mri_21, :mri_22, :mri_23]
14
13
  end
15
14
 
16
15
  gemspec :path => "../"
@@ -1,11 +1,42 @@
1
1
  require 'active_record'
2
2
  require 'active_record/version'
3
3
  require 'active_support/core_ext/module'
4
- require 'action_view'
4
+
5
+ begin
6
+ require 'rails/engine'
7
+ require 'acts_as_taggable_on/engine'
8
+ rescue LoadError
9
+
10
+ end
5
11
 
6
12
  require 'digest/sha1'
7
13
 
8
14
  module ActsAsTaggableOn
15
+ extend ActiveSupport::Autoload
16
+
17
+ autoload :Tag
18
+ autoload :TagList
19
+ autoload :GenericParser
20
+ autoload :DefaultParser
21
+ autoload :Taggable
22
+ autoload :Tagger
23
+ autoload :Tagging
24
+ autoload :TagsHelper
25
+ autoload :VERSION
26
+
27
+ autoload_under 'taggable' do
28
+ autoload :Cache
29
+ autoload :Collection
30
+ autoload :Core
31
+ autoload :Dirty
32
+ autoload :Ownership
33
+ autoload :Related
34
+ end
35
+
36
+ autoload :Utils
37
+ autoload :Compatibility
38
+
39
+
9
40
  class DuplicateTagError < StandardError
10
41
  end
11
42
 
@@ -16,7 +47,7 @@ module ActsAsTaggableOn
16
47
 
17
48
  def self.method_missing(method_name, *args, &block)
18
49
  @configuration.respond_to?(method_name) ?
19
- @configuration.send(method_name, *args, &block) : super
50
+ @configuration.send(method_name, *args, &block) : super
20
51
  end
21
52
 
22
53
  def self.respond_to?(method_name, include_private=false)
@@ -30,8 +61,10 @@ module ActsAsTaggableOn
30
61
  end
31
62
 
32
63
  class Configuration
33
- attr_accessor :delimiter, :force_lowercase, :force_parameterize,
34
- :strict_case_match, :remove_unused_tags
64
+ attr_accessor :force_lowercase, :force_parameterize,
65
+ :remove_unused_tags, :default_parser,
66
+ :tags_counter
67
+ attr_reader :delimiter, :strict_case_match
35
68
 
36
69
  def initialize
37
70
  @delimiter = ','
@@ -39,32 +72,55 @@ module ActsAsTaggableOn
39
72
  @force_parameterize = false
40
73
  @strict_case_match = false
41
74
  @remove_unused_tags = false
75
+ @tags_counter = true
76
+ @default_parser = DefaultParser
77
+ @force_binary_collation = false
42
78
  end
43
- end
44
79
 
45
- setup
46
- end
80
+ def strict_case_match=(force_cs)
81
+ @strict_case_match = force_cs unless @force_binary_collation
82
+ end
83
+
84
+ def delimiter=(string)
85
+ ActiveRecord::Base.logger.warn <<WARNING
86
+ ActsAsTaggableOn.delimiter is deprecated \
87
+ and will be removed from v4.0+, use \
88
+ a ActsAsTaggableOn.default_parser instead
89
+ WARNING
90
+ @delimiter = string
91
+ end
92
+
93
+ def force_binary_collation=(force_bin)
94
+ if Utils.using_mysql?
95
+ if force_bin
96
+ Configuration.apply_binary_collation(true)
97
+ @force_binary_collation = true
98
+ @strict_case_match = true
99
+ else
100
+ Configuration.apply_binary_collation(false)
101
+ @force_binary_collation = false
102
+ end
103
+ end
104
+ end
47
105
 
48
- require 'acts_as_taggable_on/utils'
106
+ def self.apply_binary_collation(bincoll)
107
+ if Utils.using_mysql?
108
+ coll = 'utf8_general_ci'
109
+ coll = 'utf8_bin' if bincoll
110
+ begin
111
+ ActiveRecord::Migration.execute("ALTER TABLE #{Tag.table_name} MODIFY name varchar(255) CHARACTER SET utf8 COLLATE #{coll};")
112
+ rescue Exception => e
113
+ puts "Trapping #{e.class}: collation parameter ignored while migrating for the first time."
114
+ end
115
+ end
116
+ end
49
117
 
50
- require 'acts_as_taggable_on/taggable'
51
- require 'acts_as_taggable_on/acts_as_taggable_on/compatibility'
52
- require 'acts_as_taggable_on/acts_as_taggable_on/core'
53
- require 'acts_as_taggable_on/acts_as_taggable_on/collection'
54
- require 'acts_as_taggable_on/acts_as_taggable_on/cache'
55
- require 'acts_as_taggable_on/acts_as_taggable_on/ownership'
56
- require 'acts_as_taggable_on/acts_as_taggable_on/related'
57
- require 'acts_as_taggable_on/acts_as_taggable_on/dirty'
118
+ end
58
119
 
59
- require 'acts_as_taggable_on/tagger'
60
- require 'acts_as_taggable_on/tag'
61
- require 'acts_as_taggable_on/tag_list'
62
- require 'acts_as_taggable_on/tags_helper'
63
- require 'acts_as_taggable_on/tagging'
64
- require 'acts_as_taggable_on/engine'
120
+ setup
121
+ end
65
122
 
66
123
  ActiveSupport.on_load(:active_record) do
67
- extend ActsAsTaggableOn::Compatibility
68
124
  extend ActsAsTaggableOn::Taggable
69
125
  include ActsAsTaggableOn::Tagger
70
126
  end
@@ -0,0 +1,79 @@
1
+ module ActsAsTaggableOn
2
+ ##
3
+ # Returns a new TagList using the given tag string.
4
+ #
5
+ # Example:
6
+ # tag_list = ActsAsTaggableOn::DefaultParser.parse("One , Two, Three")
7
+ # tag_list # ["One", "Two", "Three"]
8
+ class DefaultParser < GenericParser
9
+
10
+ def parse
11
+ string = @tag_list
12
+
13
+ string = string.join(ActsAsTaggableOn.glue) if string.respond_to?(:join)
14
+ TagList.new.tap do |tag_list|
15
+ string = string.to_s.dup
16
+
17
+ string.gsub!(double_quote_pattern) {
18
+ # Append the matched tag to the tag list
19
+ tag_list << Regexp.last_match[2]
20
+ # Return the matched delimiter ($3) to replace the matched items
21
+ ''
22
+ }
23
+
24
+ string.gsub!(single_quote_pattern) {
25
+ # Append the matched tag ($2) to the tag list
26
+ tag_list << Regexp.last_match[2]
27
+ # Return an empty string to replace the matched items
28
+ ''
29
+ }
30
+
31
+ # split the string by the delimiter
32
+ # and add to the tag_list
33
+ tag_list.add(string.split(Regexp.new delimiter))
34
+ end
35
+ end
36
+
37
+
38
+ # private
39
+ def delimiter
40
+ # Parse the quoted tags
41
+ d = ActsAsTaggableOn.delimiter
42
+ # Separate multiple delimiters by bitwise operator
43
+ d = d.join('|') if d.kind_of?(Array)
44
+ d
45
+ end
46
+
47
+ # ( # Tag start delimiter ($1)
48
+ # \A | # Either string start or
49
+ # #{delimiter} # a delimiter
50
+ # )
51
+ # \s*" # quote (") optionally preceded by whitespace
52
+ # (.*?) # Tag ($2)
53
+ # "\s* # quote (") optionally followed by whitespace
54
+ # (?= # Tag end delimiter (not consumed; is zero-length lookahead)
55
+ # #{delimiter}\s* | # Either a delimiter optionally followed by whitespace or
56
+ # \z # string end
57
+ # )
58
+ def double_quote_pattern
59
+ /(\A|#{delimiter})\s*"(.*?)"\s*(?=#{delimiter}\s*|\z)/
60
+ end
61
+
62
+ # ( # Tag start delimiter ($1)
63
+ # \A | # Either string start or
64
+ # #{delimiter} # a delimiter
65
+ # )
66
+ # \s*' # quote (') optionally preceded by whitespace
67
+ # (.*?) # Tag ($2)
68
+ # '\s* # quote (') optionally followed by whitespace
69
+ # (?= # Tag end delimiter (not consumed; is zero-length lookahead)
70
+ # #{delimiter}\s* | d # Either a delimiter optionally followed by whitespace or
71
+ # \z # string end
72
+ # )
73
+ def single_quote_pattern
74
+ /(\A|#{delimiter})\s*'(.*?)'\s*(?=#{delimiter}\s*|\z)/
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -1,4 +1,3 @@
1
- require 'rails/engine'
2
1
  module ActsAsTaggableOn
3
2
  class Engine < Rails::Engine
4
3
  end
@@ -0,0 +1,19 @@
1
+ module ActsAsTaggableOn
2
+ ##
3
+ # Returns a new TagList using the given tag string.
4
+ #
5
+ # Example:
6
+ # tag_list = ActsAsTaggableOn::GenericParser.new.parse("One , Two, Three")
7
+ # tag_list # ["One", "Two", "Three"]
8
+ class GenericParser
9
+ def initialize(tag_list)
10
+ @tag_list = tag_list
11
+ end
12
+
13
+ def parse
14
+ TagList.new.tap do |tag_list|
15
+ tag_list.add @tag_list.split(',').map(&:strip).reject(&:empty?)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,12 +1,10 @@
1
- # coding: utf-8
1
+ # encoding: utf-8
2
2
  module ActsAsTaggableOn
3
3
  class Tag < ::ActiveRecord::Base
4
4
 
5
- attr_accessible :name if defined?(ActiveModel::MassAssignmentSecurity)
6
-
7
5
  ### ASSOCIATIONS:
8
6
 
9
- has_many :taggings, dependent: :destroy, class_name: 'ActsAsTaggableOn::Tagging'
7
+ has_many :taggings, dependent: :destroy, class_name: '::ActsAsTaggableOn::Tagging'
10
8
 
11
9
  ### VALIDATIONS:
12
10
 
@@ -20,6 +18,8 @@ module ActsAsTaggableOn
20
18
  end
21
19
 
22
20
  ### SCOPES:
21
+ scope :most_used, ->(limit = 20) { order('taggings_count desc').limit(limit) }
22
+ scope :least_used, ->(limit = 20) { order('taggings_count asc').limit(limit) }
23
23
 
24
24
  def self.named(name)
25
25
  if ActsAsTaggableOn.strict_case_match
@@ -30,17 +30,10 @@ module ActsAsTaggableOn
30
30
  end
31
31
 
32
32
  def self.named_any(list)
33
- if ActsAsTaggableOn.strict_case_match
34
- clause = list.map { |tag|
35
- sanitize_sql(["name = #{binary}?", as_8bit_ascii(tag)])
36
- }.join(' OR ')
37
- where(clause)
38
- else
39
- clause = list.map { |tag|
40
- sanitize_sql(['LOWER(name) = LOWER(?)', as_8bit_ascii(unicode_downcase(tag))])
41
- }.join(' OR ')
42
- where(clause)
43
- end
33
+ clause = list.map { |tag|
34
+ sanitize_sql_for_named_any(tag).force_encoding('BINARY')
35
+ }.join(' OR ')
36
+ where(clause)
44
37
  end
45
38
 
46
39
  def self.named_like(name)
@@ -55,6 +48,12 @@ module ActsAsTaggableOn
55
48
  where(clause)
56
49
  end
57
50
 
51
+ def self.for_context(context)
52
+ joins(:taggings).
53
+ where(["taggings.context = ?", context]).
54
+ select("DISTINCT tags.*")
55
+ end
56
+
58
57
  ### CLASS METHODS:
59
58
 
60
59
  def self.find_or_create_with_like_by_name(name)
@@ -101,6 +100,9 @@ module ActsAsTaggableOn
101
100
  end
102
101
 
103
102
  class << self
103
+
104
+
105
+
104
106
  private
105
107
 
106
108
  def comparable_name(str)
@@ -130,6 +132,14 @@ module ActsAsTaggableOn
130
132
  string.to_s.mb_chars
131
133
  end
132
134
  end
135
+
136
+ def sanitize_sql_for_named_any(tag)
137
+ if ActsAsTaggableOn.strict_case_match
138
+ sanitize_sql(["name = #{binary}?", as_8bit_ascii(tag)])
139
+ else
140
+ sanitize_sql(['LOWER(name) = LOWER(?)', as_8bit_ascii(unicode_downcase(tag))])
141
+ end
142
+ end
133
143
  end
134
144
  end
135
145
  end
@@ -1,89 +1,16 @@
1
+
1
2
  require 'active_support/core_ext/module/delegation'
2
3
 
3
4
  module ActsAsTaggableOn
4
5
  class TagList < Array
5
6
  attr_accessor :owner
7
+ attr_accessor :parser
6
8
 
7
9
  def initialize(*args)
10
+ @parser = ActsAsTaggableOn.default_parser
8
11
  add(*args)
9
12
  end
10
13
 
11
- class << self
12
- ##
13
- # Returns a new TagList using the given tag string.
14
- #
15
- # Example:
16
- # tag_list = ActsAsTaggableOn::TagList.from("One , Two, Three")
17
- # tag_list # ["One", "Two", "Three"]
18
- def from(string)
19
- string = string.join(ActsAsTaggableOn.glue) if string.respond_to?(:join)
20
-
21
- new.tap do |tag_list|
22
- string = string.to_s.dup
23
-
24
-
25
- string.gsub!(double_quote_pattern) {
26
- # Append the matched tag to the tag list
27
- tag_list << Regexp.last_match[2]
28
- # Return the matched delimiter ($3) to replace the matched items
29
- ''
30
- }
31
-
32
- string.gsub!(single_quote_pattern) {
33
- # Append the matched tag ($2) to the tag list
34
- tag_list << Regexp.last_match[2]
35
- # Return an empty string to replace the matched items
36
- ''
37
- }
38
-
39
- # split the string by the delimiter
40
- # and add to the tag_list
41
- tag_list.add(string.split(Regexp.new delimiter))
42
- end
43
- end
44
-
45
- def delimiter
46
- # Parse the quoted tags
47
- d = ActsAsTaggableOn.delimiter
48
- # Separate multiple delimiters by bitwise operator
49
- d = d.join('|') if d.kind_of?(Array)
50
-
51
- d
52
- end
53
-
54
- def single_quote_pattern
55
- %r{
56
- ( # Tag start delimiter ($1)
57
- \A | # Either string start or
58
- #{delimiter} # a delimiter
59
- )
60
- \s*' # quote (') optionally preceded by whitespace
61
- (.*?) # Tag ($2)
62
- '\s* # quote (') optionally followed by whitespace
63
- (?= # Tag end delimiter (not consumed; is zero-length lookahead)
64
- #{delimiter}\s* | # Either a delimiter optionally followed by whitespace or
65
- \z # string end
66
- )
67
- }x
68
- end
69
-
70
- def double_quote_pattern
71
- %r{
72
- ( # Tag start delimiter ($1)
73
- \A | # Either string start or
74
- #{delimiter} # a delimiter
75
- )
76
- \s*" # quote (") optionally preceded by whitespace
77
- (.*?) # Tag ($2)
78
- "\s* # quote (") optionally followed by whitespace
79
- (?= # Tag end delimiter (not consumed; is zero-length lookahead)
80
- #{delimiter}\s* | # Either a delimiter optionally followed by whitespace or
81
- \z # string end
82
- )
83
- }x
84
- end
85
-
86
- end
87
14
  ##
88
15
  # Add tags to the tag_list. Duplicate or blank tags will be ignored.
89
16
  # Use the <tt>:parse</tt> option to add an unparsed tag string.
@@ -149,27 +76,30 @@ module ActsAsTaggableOn
149
76
 
150
77
  private
151
78
 
152
- # Remove whitespace, duplicates, and blanks.
79
+ # Convert everything to string, remove whitespace, duplicates, and blanks.
153
80
  def clean!
154
81
  reject!(&:blank?)
82
+ map!(&:to_s)
155
83
  map!(&:strip)
156
84
  map! { |tag| tag.mb_chars.downcase.to_s } if ActsAsTaggableOn.force_lowercase
157
85
  map!(&:parameterize) if ActsAsTaggableOn.force_parameterize
158
86
 
159
- uniq!
87
+ ActsAsTaggableOn.strict_case_match ? uniq! : uniq!{ |tag| tag.downcase }
88
+ self
160
89
  end
161
90
 
162
91
 
163
92
  def extract_and_apply_options!(args)
164
93
  options = args.last.is_a?(Hash) ? args.pop : {}
165
- options.assert_valid_keys :parse
94
+ options.assert_valid_keys :parse, :parser
95
+
96
+ parser = options[:parser] ? options[:parser] : @parser
166
97
 
167
- args.map! { |a| self.class.from(a) } if options[:parse]
98
+ args.map! { |a| parser.new(a).parse } if options[:parse] || options[:parser]
168
99
 
169
100
  args.flatten!
170
101
  end
171
102
 
172
-
173
103
  end
174
104
  end
175
105
 
@@ -31,6 +31,7 @@ module ActsAsTaggableOn::Taggable
31
31
  # to mimic the underlying behavior. While processing this first
32
32
  # call to columns, we do the caching column check and dynamically add
33
33
  # the class and instance methods
34
+ # FIXME: this method cannot compile in rubinius
34
35
  def columns
35
36
  @acts_as_taggable_on_cache_columns ||= begin
36
37
  db_columns = super
@@ -39,6 +40,10 @@ module ActsAsTaggableOn::Taggable
39
40
  end
40
41
  end
41
42
 
43
+ def reset_column_information
44
+ super
45
+ @acts_as_taggable_on_cache_columns = nil
46
+ end
42
47
  end
43
48
  end
44
49
 
@@ -68,7 +73,7 @@ module ActsAsTaggableOn::Taggable
68
73
  tag_types.map(&:to_s).each do |tag_type|
69
74
  if self.class.send("caching_#{tag_type.singularize}_list?")
70
75
  if tag_list_cache_set_on(tag_type)
71
- list = tag_list_cache_on(tag_type).to_a.flatten.compact.join(', ')
76
+ list = tag_list_cache_on(tag_type).to_a.flatten.compact.join("#{ActsAsTaggableOn.delimiter} ")
72
77
  self["cached_#{tag_type.singularize}_list"] = list
73
78
  end
74
79
  end
@@ -53,6 +53,7 @@ module ActsAsTaggableOn::Taggable
53
53
  # * :order - A piece of SQL to order by. Eg 'tags.count desc' or 'taggings.created_at desc'
54
54
  # * :on - Scope the find to only include a certain context
55
55
  def all_tags(options = {})
56
+ options = options.dup
56
57
  options.assert_valid_keys :start_at, :end_at, :conditions, :order, :limit, :on
57
58
 
58
59
  ## Generate conditions:
@@ -87,6 +88,7 @@ module ActsAsTaggableOn::Taggable
87
88
  # * :at_most - Exclude tags with a frequency greater than the given value
88
89
  # * :on - Scope the find to only include a certain context
89
90
  def all_tag_counts(options = {})
91
+ options = options.dup
90
92
  options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on, :id
91
93
 
92
94
  ## Generate conditions:
@@ -133,10 +135,10 @@ module ActsAsTaggableOn::Taggable
133
135
  table_name_pkey = "#{table_name}.#{primary_key}"
134
136
  if ActsAsTaggableOn::Utils.using_mysql?
135
137
  # See https://github.com/mbleigh/acts-as-taggable-on/pull/457 for details
136
- scoped_ids = select(table_name_pkey).map(&:id)
138
+ scoped_ids = pluck(table_name_pkey)
137
139
  tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN (?)", scoped_ids)
138
140
  else
139
- tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{safe_to_sql(select(table_name_pkey))})")
141
+ tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{safe_to_sql(except(:select).select(table_name_pkey))})")
140
142
  end
141
143
 
142
144
  tagging_scope
@@ -167,9 +169,12 @@ module ActsAsTaggableOn::Taggable
167
169
  end
168
170
 
169
171
  module CalculationMethods
170
- def count(column_name=:all)
172
+ # Rails 5 TODO: Remove options argument as soon we remove support to
173
+ # activerecord-deprecated_finders.
174
+ # See https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/calculations.rb#L38
175
+ def count(column_name = :all, options = {})
171
176
  # https://github.com/rails/rails/commit/da9b5d4a8435b744fcf278fffd6d7f1e36d4a4f2
172
- super
177
+ ActsAsTaggableOn::Utils.active_record5? ? super(column_name) : super(column_name, options)
173
178
  end
174
179
  end
175
180
  end