Rails のバリデーションには特定のコンテキストのときだけ実行させることができる on
オプションが存在している。
validates :field1, presence: true
validates :field2, presence: true
validates :field3, presence: true, on: :admin
こうすると、 valid?(:admin)
のときだけは全てのフィールドが必須入力となるが、そうでない場合は field1
、field2
のみ必須となり、 field3
は任意入力になる。なるほど、便利だ。
ところが、これを逆転させたいとき、即ち :admin
コンテキストのとき「だけ」field3
を任意入力にしたいとなると、途端に面倒なことになる。
validates :field1, presence: true
validates :field2, presence: true
validates :field3, presence: true, on: [:create, :update, :context_foo, :context_bar]
おおう。これ、 :context_baz
が増えたら、ここもメンテナンスせなあかんのか? ちょっとそれはなくない? このコードからは「:admin
コンテキストの時だけ任意入力」という意図が全く読み取れない(そもそも :admin
が出てこないではないか)ので、適切にメンテナンスするのは無理がある。
で、Rails の実装を確認してみると、どうやら on
オプションは if
に読み替えて実装されているらしい。
def validate(*args, &block)
options = args.extract_options!
if options.key?(:on)
options = options.dup
options[:if] = Array(options[:if])
options[:if].unshift lambda { |o|
Array(options[:on]).include?(o.validation_context)
}
end
args << options
set_callback(:validate, *args, &block)
end
なるほど。では unless
にすれば意味が反転するはずだ。
validates :field1, presence: true
validates :field2, presence: true
validates :field3, presence: true, unless: proc { [:admin].include?(validation_context) }
できた。若干・・・というか大分面倒ではあるが、将来増えるかもわからないコンテキストをすべて列挙するよりは、余程現実的だろう。
off
とか not_on
のようなオプションで標準サポートされていても良さそうなものだが、何か課題や Rails 哲学に反する点でもあるのだろうか。そもそもとして、このようなことが必要になるのはモデルの設計が悪いとか、コンテキストの使い方を間違っているとか、そういう話なのかもしれないが、そうは言っても現実というものは理想とは程遠いもんである。