QA@IT

Rails + MySQL でデータの制約を厳しくする方法

3255 PV

http://qa.atmarkit.co.jp/q/2395 で「歴史的にMySQLではデータの制約がゆるいので、例外を投げずに値をcoerceして保持することがある。」という話がありましたが、制約を厳しくて例外を投げさせるようにするには、どういう設定をすれば良いのでしょうか?

気付いた範囲では以下のようなことがあったのを防ぎたいですが、他にもはまりどころがあれば防ぎたいです。

  • 長過ぎるデータを保存したら末尾が切れていた。
  • fixtures に created_at や updated_at を書いていなかったら MySQL では 0000-00-00 00:00:00 になっていて、 rails 側では nil になっていた。同じ fixtures を PostgreSQL で load しようとしたら NOT NULL 制約に引っかかって load できなかった。

回答

現在のRails masterブランチ(将来的にRails4というバージョンでリリースされるはず)では、
下記のPull Requestによって、"SQL_MODE='STRICT_ALL_TABLES'を設定するようになります。

https://github.com/rails/rails/pull/6069

新機能なので、Rails 3.2以下のバージョンにはバックポートされないとおもいますが、
記述されているモンキーパッチでRailsレベルでも設定できるようです。

編集 履歴 (0)
  • ありがとうございます。
    モンキーパッチで設定出来たようなので、これで試してみます。
    -

ruby とは関係ないですが、mysql にストリクトモードというものがあります。
set session sql_mode = 'STRICT_ALL_TABLES' のように指定します。
my.cnf で指定することも出来たと思います。

create table hoge (
  id int not null primary key auto_increment,
  val varchar(3) not null,
  dt datetime not null
);

insert into hoge (val) values ('1234');
> Warning (Code 1364): Field 'dt' doesn't have a default value
> Warning (Code 1265): Data truncated for column 'val' at row 1

select * from hoge;
> +----+-----+---------------------+
> | id | val | dt                  |
> +----+-----+---------------------+
> |  1 | 123 | 0000-00-00 00:00:00 |
> +----+-----+---------------------+

set session sql_mode = 'STRICT_ALL_TABLES';

insert into hoge (val) values ('1234');
> ERROR 1364 (HY000): Field 'dt' doesn't have a default value

insert into hoge (val, dt) values ('1234', NOW());
> ERROR 1406 (22001): Data too long for column 'val' at row 1
編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。