railsのモデルに、特定の条件下で動くvalidationを追加
ifを使用した条件分岐
例えば、bという項目がtrueの場合のみaの値は必須にしたい、とかあると思う。
with_optionsメソッドを使用して以下のように実装することができる。
class Post < ActiveRecord::Base # ifオプションで条件に合致する場合のみvalidatesを実行(published?はメソッド名またはmodelのboolean項目) validates :name, presence: true if: published? # 複数valitatesをまとめたい場合はwith_optionsを使用 with_options if: :published? do validates :name, presence: true validates :category, presence: true end # unlessで条件に合致しない場合のみvalidatesを実行 # lambdaを使うことで複数条件を指定できる with_options unless: -> { :hoge? || :foo? } do validates :name, presence: true end end
ただし、この場合、with_optionsブロック内部で更にif: を使用してしまうと、
内部のif条件の場合にしかvalidatesが実行されなくなる。
# hogeの時しかwith_options内部が実行されない with_options if: :published? do validates :name, presence: true validates :category, presence: true, if: hoge end # with_optionsで定義したものと逆のもの(この場合はunless)を使用すれば問題ない with_options if: :published? do validates :name, presence: true validates :category, presence: true, unless: 'hoge.blank?' end
ネストしたvalidationを記載するなら、メソッドを一つ作って指定した方が良さそう。
validates :name, presence: true, if: :require_validation? def require_validation? return true if aaa? && bbb? false end
onを使用した条件分岐
例えば新規登録(create)の場合のみバリデーションをかけたい時は、onオプションを使用する。
class Post < ActiveRecord::Base # createの時のみ実行 validates :name, presence: true on: :create # if同様with_optionsを使用できる with_options on: :create? do validates :name, presence: true validates :category, presence: true end # こうすることで、pattern_hogeコンテキストが渡された時のみvalidatesが実行される validates :hoge, presence: true, length: { maximum: 3000 }, on: :pattern_hoge end
class PostsController < ApplicationController def hoge # pattern_hogeコンテキストを指定 post.save(context: :hoge.save(context: :pattern_validation)) end end