Help us understand the problem. What is going on with this article?

ActiveRecordでデフォルトの照合順序を変更する

More than 5 years have passed since last update.

MySQLには文字列の照合順序(collation)というのがあって、MySQL側でのcharset utf8のときのデフォルトの照合順序はutf8_general_ciです。

ActiveRecord::Migrationでは明示的に照合順序を指定しない場合、charset utf8で照合順序utf8_unicode_ciのデータベースを作成しますが、これは少なくとも日本語圏では多くの人が期待する挙動ではないと思われるので注意が必要です。

たとえば、以下のようなファミリーテーブルをrake db:migrateすると

db/migrate/20121112110702_create_families.rb
# coding: utf-8
class CreateFamilies < ActiveRecord::Migration
  def change
    create_table :families do |t| 
      t.string :name
      t.string :relationship
    end 
    # add_index :families, :relationship, unique: true
    Family.create(name: 'ユイ',   relationship: '本人')
    Family.create(name: 'キリト', relationship: 'パパ')
    Family.create(name: 'アスナ', relationship: 'ハハ')
  end 
end

utf8_unicode_ciなテーブルが作成されます。

CREATE TABLE `families` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `relationship` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
SELECT * FROM families;
+----+-----------+--------------+
| id | name      | relationship |
+----+-----------+--------------+
|  1 | ユイ      | 本人         |
|  2 | キリト    | パパ         |
|  3 | アスナ    | ハハ         |
+----+-----------+--------------+

ここで'パパ'を検索すると、utf8_unicode_ciでは'ハ'と'パ'は等価と扱われるので'ハハ'も検索に引っかかります。この挙動を期待するケースはあまり多くないのではないでしょうか。

SELECT * FROM families WHERE relationship = 'パパ';
+----+-----------+--------------+
| id | name      | relationship |
+----+-----------+--------------+
|  2 | キリト    | パパ         |
|  3 | アスナ    | ハハ         |
+----+-----------+--------------+

また、relationshipカラムにUNIQUEインデックスを張ってあると'パパ'と'ハハ'がUNIQUE制約を満たせないので以下のようにエラーになります。

Mysql2::Error: Duplicate entry 'ハハ' for key 'relationship': INSERT INTO `families` (`name`, `relationship`) VALUES ('アスナ', 'ハハ')

ということで、照合順序utf8_general_ciなデータベースを作成したいわけですが、これはコンフィグでcharsetcollationを指定するだけで簡単にいけます。

config/database.yml
development:
  adapter: mysql2
  encoding: utf8
  charset: utf8
  collation: utf8_general_ci
  reconnect: false
  database: sao_development

これでrake db:migrateすると

CREATE TABLE `families` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `relationship` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `relationship` (`relationship`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

MySQL側のデフォルトの照合順序(utf8_general_ci)で作成されて

SELECT * FROM families WHERE relationship = 'パパ';
+----+-----------+--------------+
| id | name      | relationship |
+----+-----------+--------------+
|  2 | キリト    | パパ         |
+----+-----------+--------------+

ちゃんと'パパ'だけが検索に引っかかりました!

これで家族におばあちゃんが増えても安心ですね!!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした