ifを使用した条件分岐
例えば、bという項目がtrueの場合のみaの値は必須にしたい、とかあると思う。
if: オプションを使えばいいのだけれど、複数バリデーションまとめて判定させたい場合は、
with_optionsメソッドを使用して以下のように実装することができる。
post.rb
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オプションを使用する。
post.rb
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
posts_controller.rb
class PostsController < ApplicationController
def hoge
# pattern_hogeコンテキストを指定
post.save(context: :hoge.save(context: :pattern_validation))
end
end