diff --git a/CHANGELOG.md b/CHANGELOG.md index 4302864c2..cb315e8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ As such, a _Feature_ would map to either major or minor. A _bug fix_ to a patch. * Performance * Misc +### [3.4.4 / 2015-02-26](v3.4.4...v3.4.5) +* Fixes + * [@rikettsie Fixed collation for MySql](https://github.com/mbleigh/acts-as-taggable-on/pull/634) + ### [3.4.4 / 2015-02-11](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.3...v3.4.4) * Fixes diff --git a/Gemfile b/Gemfile index c0a52c86c..2e4f2ec78 100644 --- a/Gemfile +++ b/Gemfile @@ -8,4 +8,4 @@ group :local_development do gem 'appraisal' gem 'rake' gem 'byebug' , platform: :mri_21 -end \ No newline at end of file +end diff --git a/README.md b/README.md index 005b88900..9c26aab55 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,22 @@ Review the generated migrations then migrate : rake db:migrate ``` +#### For MySql users +You can circumvent at any time the problem of special characters [issue 623](https://github.com/mbleigh/acts-as-taggable-on/issues/623) by setting in an initializer file: + +```ruby +ActsAsTaggableOn.force_binary_collation = true +``` + +Or by running this rake task: + +```shell +rake acts_as_taggable_on_engine:tag_names:collate_bin +``` + +See the Configuration section for more details, and a general note valid for older +version of the gem. + #### Upgrading see [UPGRADING](UPGRADING.md) @@ -407,13 +423,28 @@ If you would like tags to be case-sensitive and not use LIKE queries for creatio ActsAsTaggableOn.strict_case_match = true ``` +If you would like to have an exact match covering special characters with MySql: + +```ruby +ActsAsTaggableOn.force_binary_collation = true +``` + If you want to change the default delimiter (it defaults to ','). You can also pass in an array of delimiters such as ([',', '|']): ```ruby ActsAsTaggableOn.delimiter = ',' ``` -*NOTE: SQLite by default can't upcase or downcase multibyte characters, resulting in unwanted behavior. Load the SQLite ICU extension for proper handle of such characters. [See docs](http://www.sqlite.org/src/artifact?ci=trunk&filename=ext/icu/README.txt)* +*NOTE 1: SQLite by default can't upcase or downcase multibyte characters, resulting in unwanted behavior. Load the SQLite ICU extension for proper handle of such characters. [See docs](http://www.sqlite.org/src/artifact?ci=trunk&filename=ext/icu/README.txt)* + +*NOTE 2: the option `force_binary_collation` is strongest than `strict_case_match` and when +set to true, the `strict_case_match` is ignored. +To roughly apply the `force_binary_collation` behaviour with a version of the gem <= 3.4.4, execute the following commands in the MySql console:* + +```shell +USE my_wonderful_app_db; +ALTER TABLE tags MODIFY name VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_bin; +``` ## Contributors diff --git a/Rakefile b/Rakefile index 9e58213f4..f9902ffc6 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,8 @@ require 'rubygems' require 'bundler/setup' +import "./lib/tasks/tags_collate_utf8.rake" + desc 'Default: run specs' task default: :spec diff --git a/lib/acts-as-taggable-on.rb b/lib/acts-as-taggable-on.rb index 3b5b095cf..c5e34d416 100644 --- a/lib/acts-as-taggable-on.rb +++ b/lib/acts-as-taggable-on.rb @@ -69,6 +69,13 @@ def initialize @remove_unused_tags = false @tags_counter = true @default_parser = DefaultParser + @force_binary_collation = false + end + + def strict_case_match=(force_cs) + if @force_binary_collation == false + @strict_case_match = force_cs + end end def delimiter=(string) @@ -79,6 +86,30 @@ def delimiter=(string) WARNING @delimiter = string end + + def force_binary_collation=(force_bin) + if Utils.using_mysql? + if force_bin == true + Configuration.apply_binary_collation(true) + @force_binary_collation = true + @strict_case_match = true + else + Configuration.apply_binary_collation(false) + @force_binary_collation = false + end + end + end + + def self.apply_binary_collation(bincoll) + if Utils.using_mysql? + coll = 'utf8_general_ci' + if bincoll == true + coll = 'utf8_bin' + end + ActiveRecord::Migration.execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE #{coll};") + end + end + end setup diff --git a/lib/tasks/tags_collate_utf8.rake b/lib/tasks/tags_collate_utf8.rake new file mode 100644 index 000000000..70730c442 --- /dev/null +++ b/lib/tasks/tags_collate_utf8.rake @@ -0,0 +1,21 @@ +# These rake tasks are to be run by MySql users only, they fix the management of +# binary-encoded strings for tag 'names'. Issues: +# https://github.com/mbleigh/acts-as-taggable-on/issues/623 + +namespace :acts_as_taggable_on_engine do + + namespace :tag_names do + + desc "Forcing collate of tag names to utf8_bin" + task :collate_bin => [:environment] do |t, args| + ActsAsTaggableOn::Configuration.apply_binary_collation(true) + end + + desc "Forcing collate of tag names to utf8_general_ci" + task :collate_ci => [:environment] do |t, args| + ActsAsTaggableOn::Configuration.apply_binary_collation(false) + end + + end + +end diff --git a/spec/acts_as_taggable_on/tag_spec.rb b/spec/acts_as_taggable_on/tag_spec.rb index c2684f6bf..48eb1a3f5 100644 --- a/spec/acts_as_taggable_on/tag_spec.rb +++ b/spec/acts_as_taggable_on/tag_spec.rb @@ -2,8 +2,11 @@ require 'spec_helper' require 'db/migrate/2_add_missing_unique_indices.rb' + shared_examples_for 'without unique index' do - prepend_before(:all) { AddMissingUniqueIndices.down } + prepend_before(:all) do + AddMissingUniqueIndices.down + end append_after(:all) do ActsAsTaggableOn::Tag.delete_all AddMissingUniqueIndices.up @@ -309,7 +312,7 @@ tag.save! end end - + it 'should find the most popular tags' do expect(ActsAsTaggableOn::Tag.most_used(3).first.name).to eq("golden_syrup") expect(ActsAsTaggableOn::Tag.most_used(3).length).to eq(3) @@ -320,4 +323,5 @@ expect(ActsAsTaggableOn::Tag.least_used(3).length).to eq(3) end end + end