2011-12-05
_ Rails3 と MySQL な環境で Unicode の絵文字を使う
絵文字が Unicode 6 から収録されて iPhone などから入力された絵文字なんかをデータベースに登録することも可能になった.Rails のアプリケーションを作成して,ローカルでちょっと開発するときは SQLite を利用していて,この絵文字についても特に問題なくデータベースに読み書きできていたのだけど,別のサーバーで MySQL で利用しようとしたら,絵文字以降の文字列が消えてしまう,という状態になった.
利用していた MySQL のバージョンは 5.1.絵文字は UTF-8 で 4 バイトで表されているけど,MySQL 5.1 での UTF-8 は 1 文字を 3 バイトまでをサポートしているため,絵文字を利用した場合はうまく扱ってもらえない.MySQL 5.5 からは 4 バイトまでサポートが可能な utf8mb4 というのが character set に追加されていて,こちらを利用するといいみたい.
というわけで MySQL を 5.5 にあげて試してみようとしたけど,mysql2 では utf8mb4 は対応していない encoding のようで利用することができないみたい.テーブルやカラムを utf8mb4 にしただけでは,クライアント側が utf8 ととして送信するためか,データベースに登録される文字は ???? と化けてしまう.ひとまず,登録できる形にはしてみたいなぁ,ということで,mysql2 のソースコードを見てみると,文字コードまわりの設定値を定義している部分があったので,とりあえずここに値をつっこんでみたらなんとかなりそうかな,という感じでコードを追加してみた.
diff --git a/lib/mysql2/client.rb b/lib/mysql2/client.rb index 20ed442..8497ca0 100644 --- a/lib/mysql2/client.rb +++ b/lib/mysql2/client.rb @@ -87,6 +87,7 @@ module Mysql2 "ucs2" => Encoding::UTF_16BE, "ujis" => Encoding::EucJP_ms, "utf8" => Encoding::UTF_8, + "utf8mb4" => Encoding::UTF_8, } MYSQL_CHARSET_MAP = { @@ -134,6 +135,7 @@ module Mysql2 42 => {:name => "latin7", :collation => "latin7_general_cs"}, 43 => {:name => "macce", :collation => "macce_bin"}, 44 => {:name => "cp1250", :collation => "cp1250_croatian_ci"}, + 45 => {:name => "utf8mb4", :collation => "utf8mb4_general_ci"}, 47 => {:name => "latin1", :collation => "latin1_bin"}, 48 => {:name => "latin1", :collation => "latin1_general_ci"}, 49 => {:name => "latin1", :collation => "latin1_general_cs"},
これで config/database.yml の encoding を utf8mb4 を指定できるようになった.console からのデータベースへの入出力でも絵文字は化けずに表示できるようになったし,iPhone から POST で入力した絵文字もちゃんとデータベースに入出力できるようになった.
MySQL を利用する場合にのみ必要になるケースだし,SQLite でも問題なかったように,他のデータベースエンジンではたぶんそのまま UTF-8 で特に問題はないんだろうなぁ.ローカルでちょっと動かすには SQLite ですませてしまうし,Heroku は PostgreSQL だし,そもそも最近は MongoDB とか使ってることのほうが多かったりで,あまり MySQL にふれる機会がないんだけど,ちょっと勉強になった.
ちなみに,データベースの default character set を utf8mb4 にすると Rails の場合,migration 用のテーブルの index の桁数が 1 文字 4 バイトで計算されてエラーとなるのでご注意を.(あれ,Rails 関係するのここくらいか…