背景
モデルにバリデーションを追加後、rails db:seed
を実行した時のエラーと解決策について備忘録がてら投稿します。
ユーザーからフォームの値を受け取った時、名前と画像を必須項目にしたかったため、Itemモデルに以下のバリデーションを追加しました。
validates :name, :image, presence: true
その後rails db:seed
を実行すると...
ActiveRecord::RecordInvalid: バリデーションに失敗しました: 画像を入力してください (ActiveRecord::RecordInvalid)
今までは問題なく動作していたseed実行時にエラーが発生しました。
原因
原因はバリデーションが実行されるタイミングです。
エラーが起きた時のseedファイルのコードは以下です。(一部抜粋)
item = Item.create!(name: 'name')
item.image.attach(***)
この場合、item = Item.create!(name: 'name')
の時点でバリデーションが実行され、:image
がアタッチされる前の段階のため「画像が入ってないよ」とバリデーションに引っかかってしまいます。
バリデーション実行のタイミングについてRailsガイドに記載がありました。
https://railsguides.jp/active_record_validations.html#バリデーション実行時の動作
以下のメソッドではバリデーションがトリガされ、オブジェクトが有効な場合にのみデータベースに保存されます。
- create
- create!
- save
- save!
- update
- update!
解決策
上記の6コマンドは実行時点でバリデーションも実行されるとのことです。これを踏まえ、以下のように修正しました。
item = Item.new(name: 'name')
item.image.attach(***)
item.save!
Item.create
でインスタンス作成と保存を同時に行うのではなく、一旦Item.new
で作成→画像をアタッチ→item.save!
で保存するようにしました。
この変更によりsave!
のタイミングでバリデーションが実行されます。item.image.attach(***)
後に実行されるためバリデーションエラーを回避することができました。
学び
今回のエラーから二つ学ぶことができました。
-
new
とcreate
の違い-
new
: インスタンスを作成するだけ -
create
: インスタンス作成+保存
-
- バリデーション実行のタイミング
またネタができたら投稿します:)
参考
https://railsguides.jp/active_record_validations.html#バリデーション実行時の動作