MySQLには文字列の照合順序(collation)というのがあって、MySQL側でのcharset utf8のときのデフォルトの照合順序はutf8_general_ciです。
ActiveRecord::Migrationでは明示的に照合順序を指定しない場合、charset utf8で照合順序utf8_unicode_ciのデータベースを作成しますが、これは少なくとも日本語圏では多くの人が期待する挙動ではないと思われるので注意が必要です。
たとえば、以下のようなファミリーテーブルをrake db:migrateすると
# 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なデータベースを作成したいわけですが、これはコンフィグでcharset
とcollation
を指定するだけで簡単にいけます。
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 | キリト | パパ |
+----+-----------+--------------+
ちゃんと'パパ'だけが検索に引っかかりました!
これで家族におばあちゃんが増えても安心ですね!!