diff --git a/.travis.yml b/.travis.yml index a45ae24aa..f6e49fa38 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,14 +2,17 @@ language: ruby cache: bundler addons: - postgresql: '9.4' + postgresql: '10' + +services: + - mysql + - postgresql rvm: - - ruby-head - - 2.5.1 - - 2.4.4 + - 2.6.5 + - 2.5.5 + - 2.4.6 - 2.3.7 - - 2.2.7 env: - DB=sqlite3 @@ -22,13 +25,10 @@ gemfile: - gemfiles/activerecord_5.0.gemfile - gemfiles/activerecord_6.0.gemfile -sudo: false - bundler_args: '--without local_development --jobs 3 --retry 3' before_install: - - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true - - gem install bundler -v '< 2' + - gem install bundler script: bundle exec rake @@ -37,9 +37,7 @@ matrix: - rvm: ruby-head fast_finish: true exclude: - - rvm: 2.2.7 - gemfile: gemfiles/activerecord_6.0.gemfile - rvm: 2.3.7 gemfile: gemfiles/activerecord_6.0.gemfile - - rvm: 2.4.4 + - rvm: 2.4.6 gemfile: gemfiles/activerecord_6.0.gemfile diff --git a/acts-as-taggable-on.gemspec b/acts-as-taggable-on.gemspec index 484a0c35d..e88cbe9b8 100644 --- a/acts-as-taggable-on.gemspec +++ b/acts-as-taggable-on.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |gem| gem.files = `git ls-files`.split($/) gem.test_files = gem.files.grep(%r{^spec/}) gem.require_paths = ['lib'] - gem.required_ruby_version = '>= 2.2.7' + gem.required_ruby_version = '>= 2.3.7' if File.exist?('UPGRADING.md') gem.post_install_message = File.read('UPGRADING.md') diff --git a/gemfiles/activerecord_5.0.gemfile b/gemfiles/activerecord_5.0.gemfile index e48906999..d519519f6 100644 --- a/gemfiles/activerecord_5.0.gemfile +++ b/gemfiles/activerecord_5.0.gemfile @@ -1,5 +1,3 @@ -# This file was generated by Appraisal - source "https://rubygems.org" gem "activerecord", "~> 5.0.3" @@ -9,7 +7,7 @@ when "postgresql" when "mysql" gem 'mysql2', '~> 0.3' else - gem 'sqlite3' + gem "sqlite3", "~> 1.3", "< 1.4" end group :local_development do @@ -17,7 +15,7 @@ group :local_development do gem "guard-rspec" gem "appraisal" gem "rake" - gem "byebug", platforms: [:mri_21, :mri_22, :mri_23] + gem "byebug", platforms: [:mri] end gemspec path: "../" diff --git a/gemfiles/activerecord_5.1.gemfile b/gemfiles/activerecord_5.1.gemfile index ca8c1920c..aa0fe0587 100644 --- a/gemfiles/activerecord_5.1.gemfile +++ b/gemfiles/activerecord_5.1.gemfile @@ -1,5 +1,3 @@ -# This file was generated by Appraisal - source "https://rubygems.org" gem "activerecord", "~> 5.1.1" @@ -9,7 +7,7 @@ when "postgresql" when "mysql" gem 'mysql2', '~> 0.3' else - gem 'sqlite3' + gem "sqlite3", "~> 1.3", "< 1.4" end group :local_development do @@ -17,7 +15,7 @@ group :local_development do gem "guard-rspec" gem "appraisal" gem "rake" - gem "byebug", platforms: [:mri_21, :mri_22, :mri_23] + gem "byebug", platforms: [:mri] end gemspec path: "../" diff --git a/gemfiles/activerecord_5.2.gemfile b/gemfiles/activerecord_5.2.gemfile index fe6525fdd..4ed6f1e6c 100644 --- a/gemfiles/activerecord_5.2.gemfile +++ b/gemfiles/activerecord_5.2.gemfile @@ -1,5 +1,3 @@ -# This file was generated by Appraisal - source "https://rubygems.org" gem "activerecord", "~> 5.2.0" @@ -9,7 +7,7 @@ when "postgresql" when "mysql" gem 'mysql2', '~> 0.3' else - gem 'sqlite3' + gem "sqlite3", "~> 1.3", "< 1.4" end group :local_development do @@ -17,7 +15,7 @@ group :local_development do gem "guard-rspec" gem "appraisal" gem "rake" - gem "byebug", platforms: [:mri_21, :mri_22, :mri_23] + gem "byebug", platforms: [:mri] end gemspec path: "../" diff --git a/gemfiles/activerecord_6.0.gemfile b/gemfiles/activerecord_6.0.gemfile index c54c5a249..6f78ffcf9 100644 --- a/gemfiles/activerecord_6.0.gemfile +++ b/gemfiles/activerecord_6.0.gemfile @@ -1,8 +1,6 @@ -# This file was generated by Appraisal - source "https://rubygems.org" -gem "activerecord", "~> 6.0.0.beta1" +gem "activerecord", "~> 6.0.0" case ENV["DB"] when "postgresql" gem 'pg' @@ -17,7 +15,7 @@ group :local_development do gem "guard-rspec" gem "appraisal" gem "rake" - gem "byebug", platforms: [:mri_21, :mri_22, :mri_23] + gem "byebug", platforms: [:mri] end gemspec path: "../" diff --git a/lib/acts-as-taggable-on.rb b/lib/acts-as-taggable-on.rb index e198fa95c..3e6a6d9d3 100644 --- a/lib/acts-as-taggable-on.rb +++ b/lib/acts-as-taggable-on.rb @@ -31,6 +31,7 @@ module ActsAsTaggableOn autoload :Dirty autoload :Ownership autoload :Related + autoload :TagListType end autoload :Utils diff --git a/lib/acts_as_taggable_on/tag.rb b/lib/acts_as_taggable_on/tag.rb index 1cce87184..f1e0e3b3f 100644 --- a/lib/acts_as_taggable_on/tag.rb +++ b/lib/acts_as_taggable_on/tag.rb @@ -105,8 +105,6 @@ def count class << self - - private def comparable_name(str) @@ -121,20 +119,12 @@ def binary ActsAsTaggableOn::Utils.using_mysql? ? 'BINARY ' : nil end - def unicode_downcase(string) - if ActiveSupport::Multibyte::Unicode.respond_to?(:downcase) - ActiveSupport::Multibyte::Unicode.downcase(string) - else - ActiveSupport::Multibyte::Chars.new(string).downcase.to_s - end + def as_8bit_ascii(string) + string.to_s.mb_chars end - def as_8bit_ascii(string) - if defined?(Encoding) - string.to_s.dup.force_encoding('BINARY') - else - string.to_s.mb_chars - end + def unicode_downcase(string) + as_8bit_ascii(string).downcase end def sanitize_sql_for_named_any(tag) diff --git a/lib/acts_as_taggable_on/taggable/core.rb b/lib/acts_as_taggable_on/taggable/core.rb index f0d88035b..83195f7d6 100644 --- a/lib/acts_as_taggable_on/taggable/core.rb +++ b/lib/acts_as_taggable_on/taggable/core.rb @@ -1,4 +1,5 @@ require_relative 'tagged_with_query' +require_relative 'tag_list_type' module ActsAsTaggableOn::Taggable module Core @@ -38,7 +39,7 @@ def initialize_acts_as_taggable_on_core through: context_taggings, source: :tag - attribute "#{tags_type.singularize}_list".to_sym, ActiveModel::Type::Value.new + attribute "#{tags_type.singularize}_list".to_sym, ActsAsTaggableOn::Taggable::TagListType.new end taggable_mixin.class_eval <<-RUBY, __FILE__, __LINE__ + 1 @@ -49,8 +50,14 @@ def #{tag_type}_list def #{tag_type}_list=(new_tags) parsed_new_list = ActsAsTaggableOn.default_parser.new(new_tags).parse - if self.class.preserve_tag_order? || parsed_new_list.sort != #{tag_type}_list.sort - set_attribute_was('#{tag_type}_list', #{tag_type}_list) + if self.class.preserve_tag_order? || (parsed_new_list.sort != #{tag_type}_list.sort) + if ActsAsTaggableOn::Utils.legacy_activerecord? + set_attribute_was("#{tag_type}_list", #{tag_type}_list) + else + unless #{tag_type}_list_changed? + @attributes["#{tag_type}_list"] = ActiveModel::Attribute.from_user("#{tag_type}_list", #{tag_type}_list, ActsAsTaggableOn::Taggable::TagListType.new) + end + end write_attribute("#{tag_type}_list", parsed_new_list) end diff --git a/lib/acts_as_taggable_on/taggable/tag_list_type.rb b/lib/acts_as_taggable_on/taggable/tag_list_type.rb new file mode 100644 index 000000000..d53a1e3dd --- /dev/null +++ b/lib/acts_as_taggable_on/taggable/tag_list_type.rb @@ -0,0 +1,4 @@ +module ActsAsTaggableOn::Taggable + class TagListType < ActiveModel::Type::Value + end +end diff --git a/lib/acts_as_taggable_on/utils.rb b/lib/acts_as_taggable_on/utils.rb index 3297c3a1e..c0515e7dc 100644 --- a/lib/acts_as_taggable_on/utils.rb +++ b/lib/acts_as_taggable_on/utils.rb @@ -24,6 +24,10 @@ def like_operator using_postgresql? ? 'ILIKE' : 'LIKE' end + def legacy_activerecord? + ActiveRecord.version <= Gem::Version.new('5.3.0') + end + # escape _ and % characters in strings, since these are wildcards in SQL. def escape_like(str) str.gsub(/[!%_]/) { |x| '!' + x } diff --git a/lib/acts_as_taggable_on/version.rb b/lib/acts_as_taggable_on/version.rb index 117bd0615..7a08a2a78 100644 --- a/lib/acts_as_taggable_on/version.rb +++ b/lib/acts_as_taggable_on/version.rb @@ -1,3 +1,3 @@ module ActsAsTaggableOn - VERSION = '6.0.1' + VERSION = '6.5.0' end diff --git a/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb b/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb index 7ab80cbe6..52e59c180 100644 --- a/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +++ b/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb @@ -192,7 +192,7 @@ its(:cached_glass_list) { should be_blank } context 'language taggings cache after update' do - before { @taggable.update_attributes(language_list: 'ruby, .net') } + before { @taggable.update(language_list: 'ruby, .net') } subject { @taggable } its(:language_list) { should == ['ruby', '.net']} @@ -201,7 +201,7 @@ end context 'status taggings cache after update' do - before { @taggable.update_attributes(status_list: 'happy, married') } + before { @taggable.update(status_list: 'happy, married') } subject { @taggable } its(:status_list) { should == ['happy', 'married'] } @@ -214,7 +214,7 @@ context 'glass taggings cache after update' do before do - @taggable.update_attributes(glass_list: 'rectangle, aviator') + @taggable.update(glass_list: 'rectangle, aviator') end subject { @taggable } diff --git a/spec/acts_as_taggable_on/caching_spec.rb b/spec/acts_as_taggable_on/caching_spec.rb index 9391fe96b..8db1b7884 100644 --- a/spec/acts_as_taggable_on/caching_spec.rb +++ b/spec/acts_as_taggable_on/caching_spec.rb @@ -31,40 +31,40 @@ end it 'should cache tags' do - @taggable.update_attributes(tag_list: 'awesome, epic') + @taggable.update(tag_list: 'awesome, epic') expect(@taggable.cached_tag_list).to eq('awesome, epic') - @another_taggable.update_attributes(language_list: 'ruby, .net') + @another_taggable.update(language_list: 'ruby, .net') expect(@another_taggable.cached_language_list).to eq('ruby, .net') end it 'should keep the cache' do - @taggable.update_attributes(tag_list: 'awesome, epic') + @taggable.update(tag_list: 'awesome, epic') @taggable = CachedModel.find(@taggable.id) @taggable.save! expect(@taggable.cached_tag_list).to eq('awesome, epic') end it 'should update the cache' do - @taggable.update_attributes(tag_list: 'awesome, epic') - @taggable.update_attributes(tag_list: 'awesome') + @taggable.update(tag_list: 'awesome, epic') + @taggable.update(tag_list: 'awesome') expect(@taggable.cached_tag_list).to eq('awesome') end it 'should remove the cache' do - @taggable.update_attributes(tag_list: 'awesome, epic') - @taggable.update_attributes(tag_list: '') + @taggable.update(tag_list: 'awesome, epic') + @taggable.update(tag_list: '') expect(@taggable.cached_tag_list).to be_blank end it 'should have a tag list' do - @taggable.update_attributes(tag_list: 'awesome, epic') + @taggable.update(tag_list: 'awesome, epic') @taggable = CachedModel.find(@taggable.id) expect(@taggable.tag_list.sort).to eq(%w(awesome epic).sort) end it 'should keep the tag list' do - @taggable.update_attributes(tag_list: 'awesome, epic') + @taggable.update(tag_list: 'awesome, epic') @taggable = CachedModel.find(@taggable.id) @taggable.save! expect(@taggable.tag_list.sort).to eq(%w(awesome epic).sort) @@ -95,7 +95,7 @@ end it 'should cache tags with custom delimiter' do - @taggable.update_attributes(tag_list: 'awesome; epic') + @taggable.update(tag_list: 'awesome; epic') expect(@taggable.tag_list).to eq(['awesome', 'epic']) expect(@taggable.cached_tag_list).to eq('awesome; epic') diff --git a/spec/acts_as_taggable_on/single_table_inheritance_spec.rb b/spec/acts_as_taggable_on/single_table_inheritance_spec.rb index 22ea2adb2..ef1f8d100 100644 --- a/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +++ b/spec/acts_as_taggable_on/single_table_inheritance_spec.rb @@ -150,7 +150,7 @@ inheriting_model.tag_list = 'one' inheriting_model.save! - inheriting_model.update_attributes! name: 'foo' + inheriting_model.update! name: 'foo' end it "should only join with taggable's table to check type for inherited models" do diff --git a/spec/acts_as_taggable_on/taggable_spec.rb b/spec/acts_as_taggable_on/taggable_spec.rb index a6c07cf92..f91f79aba 100644 --- a/spec/acts_as_taggable_on/taggable_spec.rb +++ b/spec/acts_as_taggable_on/taggable_spec.rb @@ -541,7 +541,7 @@ it 'should not delete tags if not updated' do model = TaggableModel.create(name: 'foo', tag_list: 'ruby, rails, programming') - model.update_attributes(name: 'bar') + model.update(name: 'bar') model.reload expect(model.tag_list.sort).to eq(%w(ruby rails programming).sort) end diff --git a/spec/acts_as_taggable_on/tagger_spec.rb b/spec/acts_as_taggable_on/tagger_spec.rb index 174af1226..4ed31f273 100644 --- a/spec/acts_as_taggable_on/tagger_spec.rb +++ b/spec/acts_as_taggable_on/tagger_spec.rb @@ -112,7 +112,7 @@ end it 'should not lose tags' do - @taggable.update_attributes(tag_list: 'ruby') + @taggable.update(tag_list: 'ruby') @user.tag(@taggable, with: 'ruby, scheme', on: :tags) [@taggable, @user].each(&:reload) @@ -120,7 +120,7 @@ expect(@taggable.all_tags_list.sort).to eq(%w(ruby scheme).sort) expect(-> { - @taggable.update_attributes(tag_list: '') + @taggable.update(tag_list: '') }).to change(ActsAsTaggableOn::Tagging, :count).by(-1) expect(@taggable.tag_list).to be_empty