seed-fuを使って初期データを作成していたのですが、ドハマリをしたのでメモっておきます。現象としては、特にエラーも出ずおかしなデータが作られているといったものです。
検証してみる
モデルのバリデーションはこんな感じでかけています。
validates :name, presence: true
試しに、初期データ作成を以下のようにコメントアウトします。
作成時にバリデーションに引っかかることを期待して、nameもコメントアウト。
User.seed do |obj|
#obj.name = "ユーザー1"
#obj.email = "test+100@gmail.com"
#obj.password = 'password'
#obj.password_confirmation = 'password'
end
u = User.first
u.update(name: 'test')
初期データ投入を実行します。
何事もなく実行されました。
» bundle exec rake db:seed_fu FILTER=users
== Filtering seed files against regexp: /users/
== Seed from /Users/hoge/projects/hoge/db/fixtures/users.rb
- User {}
え!?っと思い、ログを確認するも、特にエラーは出ていません。
[2017-05-02 15:12:03] (pida=4863) DEBUG -- : [db:seed_fu ] started
[2017-05-02 15:12:03] (pida=4863) DEBUG -- : (0.4ms) begin transaction
[2017-05-02 15:12:03] (pida=4863) DEBUG -- : User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" IS NULL LIMIT ? [["LIMIT", 1]]
[2017-05-02 15:12:03] (pida=4863) DEBUG -- : SQL (3.1ms) INSERT INTO "users" ("confirmation_token", "confirmation_sent_at", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["confirmation_token", "XoT-7mK4K8RCsvzJcH4_"], ["confirmation_sent_at", 2017-05-02 06:12:03 UTC], ["created_at", 2017-05-02 06:12:03 UTC], ["updated_at", 2017-05-02 06:12:03 UTC]]
[2017-05-02 15:12:03] (pida=4863) DEBUG -- : (1.7ms) commit transaction
[2017-05-02 15:12:03] (pida=4863) DEBUG -- : [db:seed_fu ] finished
データもちゃんと入っている。。。ちゃんとと言うか、本当は入ってほしくないんです。え!?バリデーションどこいっちゃたの?
1||||||0|||||KTsFoLHadSQf3wvGAJsZ||2017-05-02 06:27:21.799427||2017-05-02 06:27:21.799210|2017-05-02 06:27:21.799210||||0|
しかし、レコードは作成されているものの、その後で実行されているupdateによるnameは空のまま。updateはこけている模様。しかし何もエラーなし。
update時に、例外を吐くようにupdate!に、てみる。
User.seed do |obj|
#obj.name = "ユーザー1"
#obj.email = "test+100@gmail.com"
#obj.password = 'password'
#obj.password_confirmation = 'password'
end
u = User.first
u.update!(name: 'test')
同じく、実行すると標準出力にエラーがでました。
ログをみても、ロールバックされていることがわかる。
ロールバックが働いているため、レコード自身も作成されていませんでした。
[2017-05-02 15:18:28] (pida=5180) DEBUG -- : [db:seed_fu ] started
[2017-05-02 15:18:28] (pida=5180) DEBUG -- : (0.4ms) begin transaction
[2017-05-02 15:18:28] (pida=5180) DEBUG -- : User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" IS NULL LIMIT ? [["LIMIT", 1]]
[2017-05-02 15:18:28] (pida=5180) DEBUG -- : SQL (0.4ms) INSERT INTO "users" ("confirmation_token", "confirmation_sent_at", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["confirmation_token", "CnY6D24dv7zj_sRzo8Zf"], ["confirmation_sent_at", 2017-05-02 06:18:28 UTC], ["created_at", 2017-05-02 06:18:28 UTC], ["updated_at", 2017-05-02 06:18:28 UTC]]
[2017-05-02 15:18:28] (pida=5180) DEBUG -- : User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
[2017-05-02 15:18:28] (pida=5180) DEBUG -- : (1.3ms) rollback transaction
実際にアップデートされていると思い込んでいたデータが一向に更新されず、プログラムのバグかと思い、永遠にはまりました。
まとめると、
- Model.seedでデータを作る際には、モデルで設定しているバリデーションに関係なくレコードが作成される。
- ActiveRecordで取得したデータ(インスタンス)に対して、updateなどをかけるとモデルに設定しているバリデーションが働く。当然と言っちゃ当然か。
注意すること
- モデルでバリデーションを設定していても、Seedだと直接ガンガンレコードがインサートされてしまう。
- なんとなく使うのやめよう。。。ツールにはツールのポリシーがあって使う側も勉強しないとアカン、、、
課題
- seed-fuでデータを作成する際にバリデーションでチェックさせる方法はないのか?
結構、違和感の残る検証結果になってしまいました。もしそもそも使い方が間違ってるぞ!などのご指摘があれば、ご教授いただけると幸いです。