From 8b0eee68f9286c0e6ab4c0fc7f3348d4f5bdba4e 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 updated CHANGELOG added migration and rake task Add context constraint to find_related_* methods. Fixes mbleigh/acts-as-taggable-on#628 version bump added rake rule and a config parameter to force binary collation (MySql) added rake rule and a config parameter to force binary collation (MySql) applied changes added migration and rake task --- CHANGELOG.md | 7 ++-- Gemfile | 2 +- README.md | 33 ++++++++++++++++++- Rakefile | 2 ++ .../5_change_collation_for_tag_names.rb | 15 +++++++++ lib/acts-as-taggable-on.rb | 31 +++++++++++++++++ lib/tasks/tags_collate_utf8.rake | 21 ++++++++++++ spec/acts_as_taggable_on/tag_spec.rb | 4 ++- 8 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 db/migrate/5_change_collation_for_tag_names.rb create mode 100644 lib/tasks/tags_collate_utf8.rake diff --git a/CHANGELOG.md b/CHANGELOG.md index 4302864..15d0b29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,10 @@ Each change should fall into categories that would affect whether the release is 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. -### Master [changes](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.4...master) +### Master [fixes](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.4...master) - * Breaking Changes - * Features * Fixes - * Performance - * Misc + * [@rikettsie Fixed collation for MySql via rake rule or config parameter](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) diff --git a/Gemfile b/Gemfile index c0a52c8..2e4f2ec 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 005b889..9c26aab 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 9e58213..f9902ff 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/db/migrate/5_change_collation_for_tag_names.rb b/db/migrate/5_change_collation_for_tag_names.rb new file mode 100644 index 0000000..d04ea92 --- /dev/null +++ b/db/migrate/5_change_collation_for_tag_names.rb @@ -0,0 +1,15 @@ +# This migration is added to circumvent issue #623 and have special characters +# work properly +class ChangeCollationForTagNames << ActiveRecord::Migration + + def up + if ActsAsTaggableOn::Utils.using_mysql? + execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;") + end + end + + def down + + end + +end diff --git a/lib/acts-as-taggable-on.rb b/lib/acts-as-taggable-on.rb index 3b5b095..c5e34d4 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 0000000..70730c4 --- /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 c2684f6..fc215a5 100644 --- a/spec/acts_as_taggable_on/tag_spec.rb +++ b/spec/acts_as_taggable_on/tag_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' require 'db/migrate/2_add_missing_unique_indices.rb' + shared_examples_for 'without unique index' do prepend_before(:all) { AddMissingUniqueIndices.down } append_after(:all) do @@ -309,7 +310,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 +321,5 @@ expect(ActsAsTaggableOn::Tag.least_used(3).length).to eq(3) end end + end