MySQLには寿司ビール問題があります。
データベースの DEFAULT COLLATE を変更できれば一番いいんですが、それができない場合も多いと思います。
暫定対策として、COLLATE=utf8mb4_bin
なテーブルを作成するマイグレーションファイルの書き方です。
環境
- Rails 6.1.3.2
- MySQL 5.7.16
マイグレーションファイル
create_table に options: 'COLLATE utf8mb4_bin'
を渡せばOKです。
class CreateTags < ActiveRecord::Migration[6.1]
def change
create_table :tags, options: 'COLLATE utf8mb4_bin' do |t|
t.string :name, null: false, index: { unique: true }
t.timestamps
end
end
end
db/schema.rb を確認
ちゃんと collation: "utf8mb4_bin"
が入ってますね。
db/schema.rb
create_table "tags", charset: "utf8mb4", collation: "utf8mb4_bin", force: :cascade do |t|
t.string "name", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["name"], name: "index_tags_on_name", unique: true
end
テーブル構造を確認
本当に COLLATE=utf8mb4_bin
が設定されているか、mysql上でも確認してみましょう。
mysql> SHOW FULL COLUMNS FROM tags;
+------------+--------------+-------------+------+-----+---------+----------------+---------------------------------+---------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+------------+--------------+-------------+------+-----+---------+----------------+---------------------------------+---------+
| id | bigint(20) | NULL | NO | PRI | NULL | auto_increment | select,insert,update,references | |
| name | varchar(255) | utf8mb4_bin | NO | UNI | NULL | | select,insert,update,references | |
| created_at | datetime(6) | NULL | NO | | NULL | | select,insert,update,references | |
| updated_at | datetime(6) | NULL | NO | | NULL | | select,insert,update,references | |
+------------+--------------+-------------+------+-----+---------+----------------+---------------------------------+---------+
4 rows in set (0.01 sec)
name
カラムの Collation が utf8mb4_bin
になってますね。
🍣 ≠ 🍺 になっているか確認
🍣 と 🍺 をINSERTしてみましょう。
mysql> INSERT INTO tags (name, created_at, updated_at) VALUES ('🍣', NOW(), NOW());
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tags (name, created_at, updated_at) VALUES ('🍺', NOW(), NOW());
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tags;
+----+------+----------------------------+----------------------------+
| id | name | created_at | updated_at |
+----+------+----------------------------+----------------------------+
| 1 | 🍣 | 2021-07-02 11:45:15.000000 | 2021-07-02 11:45:15.000000 |
| 2 | 🍺 | 2021-07-02 11:45:30.000000 | 2021-07-02 11:45:30.000000 |
+----+------+----------------------------+----------------------------+
2 rows in set (0.00 sec)
無事両方入りました!
参考