ActiveRecordからutf8mb4
を扱えない主な理由
ActiveRecordのstring型カラムがvarchar(255)
で定義されるので、utf8mb4
ではインデックスのキープレフィックスが767byteを超えてしまう。
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
この問題をMySQLの設定とRailsへのパッチで解決する。
MySQLの設定
文字コードをutf8mb4
で運用するために、インデックスのキープレフィックスを拡張する。
-
innodb_large_prefix
をenable
にする
- 1を有効にするために、
innodb_file_format
をBarracuda
にする - 1を有効にするために、
innodb_file_per_table
をenable
にする -
innodb_default_row_format
をDYNAMIC
にする # >= 5.7.9
my.cnfのオプション
innodb_file_per_table = 1
innodb_file_format = Barracuda
innodb_large_prefix = 1
innodb_default_row_format = DYNAMIC # >= 5.7.9
MySQL5.6
いくつかのパラメータを変更する。
-
innodb_file_per_table
のデフォルトはenable
(>= 5.6.6) -
innodb_file_format
のデフォルトはAntelope
なので、Barracuda
への変更が必要 -
innodb_large_prefix
のデフォルトはdisable
なので、enable
に変更する -
innodb_default_row_format
、バージョン5.6系にこのオプションは無い- デフォルトが
COMPACT
であり、かつコンフィグから指定できない - テーブル作成時のオプションで指定してやる必要がある
- デフォルトが
MySQL5.7
5.7.9以上であるなら、デフォルト設定でよい。
-
innodb_file_per_table
のデフォルトはenable
-
innodb_file_format
のデフォルトはBarracuda
(>= 5.7.7) -
innodb_large_prefix
のデフォルトはenable
(>= 5.7.7) -
innodb_default_row_format
のデフォルトはDYNAMIC
(>= 5.7.9)
Railsの設定
MySQL5.7.9以上を利用しているならdatabase.yml
においてutf8mb4
を設定すればよく、とくべつなことをする必要はない。
database.yml
の設定
default: &default
adapter: mysql2
encoding: utf8mb4
charset: utf8mb4
collation: utf8mb4_general_ci
MySQL5.7未満では、テーブル作成時にROW_FORMAT=DYNAMIC
を渡してやらなければならない。
もしくはカラムオプションかインデックスオプションにlimit: 191
を付けてやる。
add_index :table1, :column1, length: 191
Rails4
kamipo神のモンキーパッチを使って、テーブル作成時のオプションにROW_FORMAT=DYNAMIC
を追加してやる。
テーブルのCREATEオプションとしてENGINE=InnoDB ROW_FORMAT=DYNAMIC
を追加してくれる。
ActiveSupport.on_load :active_record do
module ActiveRecord::ConnectionAdapters
class AbstractMysqlAdapter
def create_table_with_innodb_row_format(table_name, options = {})
table_options = options.merge(:options => 'ENGINE=InnoDB ROW_FORMAT=DYNAMIC')
create_table_without_innodb_row_format(table_name, table_options) do |td|
yield td if block_given?
end
end
alias_method_chain :create_table, :innodb_row_format
end
end
end
参考: http://qiita.com/kamipo/items/101aaf8159cf1470d823
しかし、db/schema.rb
にダンプされるテーブルオプションにはENGINE=InnoDB ROW_FORMAT=DYNAMIC
がついていない。
これもまたkamipo神によるactiverecord-mysql-awesome
をGemfileに追加しておくと、オプションを正しくダンプしてくれる。
RailsからMySQLのutf8mb4を扱えるようになるまでの道のりは、kamipoさんのおかげで切り開かれたと言っても過言ではないのでとっても感謝です。
余談でRails5
beta3ではデフォの状態だとRails4と同様にまだコケる。
kamipoさんのPRがたくさんマージされているので、そのうち。