From 5140c6f84f2ec1da28441e780795f6ffaac1e009 Mon Sep 17 00:00:00 2001 From: Enrico Fusto Date: Thu, 26 Feb 2015 17:55:36 +0100 Subject: [PATCH] added rake rule and a config parameter to force binary collation (MySql) added migration and rake task added rake rule and a config parameter to force binary collation (MySql) Added test for binary string collation included migration in test added self to migration moved binary collation migration to 'without unique index' context moved binary collation parameter from migration to app configuration (typo) removed import (typo) missing Configuration class name force_binary_collation change can be set by MySql users only (typo) method name using_mysql? when force_binary_collation is false, strict_case_match is not touch force_binary_collation not used in context without_unique_index updated README and simplified rake test rake task calls Configuration function updated README Gemfile cleaned cleaned READEME.md Added test for binary string collation (typo) removed import (typo) method name using_mysql? when force_binary_collation is false, strict_case_match is not touch force_binary_collation not used in context without_unique_index Gemfile cleaned --- CHANGELOG.md | 4 ++++ Gemfile | 2 +- README.md | 33 +++++++++++++++++++++++++++- Rakefile | 2 ++ lib/acts-as-taggable-on.rb | 31 ++++++++++++++++++++++++++ lib/tasks/tags_collate_utf8.rake | 21 ++++++++++++++++++ spec/acts_as_taggable_on/tag_spec.rb | 8 +++++-- 7 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 lib/tasks/tags_collate_utf8.rake 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