結論
1.saveに validate: false
を渡す
-
validate: false
を末尾に記載することで、バリデーションをskipできました。 - 加えて、無意味な
save
を2回走らせないように、find_or_create_by
からfind_or_initialize_by
に修正しました。
Model.find_or_initialize_by(name: "テスト") do |m|
m.published_at = Time.zone.today - 1 # バリデーション対象のコード
m.save(validate: false) #=> バリデーションをskipさせる
end
補足
@jnchitoさんよりコメントいただきました。
1.new_record?メソッドを使用する
ブロックの外でsave(validate: false)
を実行します。
# この時点ではsaveしない
model = Model.find_or_initialize_by(name: "テスト") do |m|
m.published_at = Time.zone.today - 1
end
# ここで初めてsaveする
model.save(validate: false) if model.new_record?
2.バリデーションを通さずに、カラムを直接更新する
update_columns
を使用することで、バリデーションを通さないで更新することができます。
# !を付けて意図しないバリデーションエラーが発生したら例外を発生させる
model = Model.find_or_create_by!(name: "テスト")
if model.published_at.nil?
# Railsのバリデーションを通さず、DB上のpublished_atカラムを直接更新する
model.update_columns(published_at: Time.zone.today - 1)
end
背景
目的
作成日よりも遅い日付のテストデータを作成したい
現状
「作成日よりも遅い日付は登録できない」というバリデーションを設定しているため、保存できない
対応策
テストデータを作成するときのみ、バリデーションをskipさせたい
改善前
find_or_create_by
でテストデータを作成していたが、バリデーション設定後、エラーするようになった。
# エラーになるコード
Model.find_or_create_by(name: "テスト") do |m|
m.published_at = Time.zone.today - 1 # 作成日よりも遅い日付を渡すと、エラーになる。
end
調査と結果
- saveメソッドにオプションを渡すことで、skipできることがわかった。
save(validate: false)
- それをブロックの最後で実行することで、skipさせることができた!
Model.find_or_create_by(name: "テスト") do |m|
# 略
m.save(validate: false) #=> 追加
end