TIM Labs

Rails のバリデーションを特定のコンテキスト「以外」で実行させる

| コメント(0) | トラックバック(0)

Rails のバリデーションには特定のコンテキストのときだけ実行させることができる on オプションが存在している。

validates :field1, presence: true
validates :field2, presence: true
validates :field3, presence: true, on: :admin

こうすると、 valid?(:admin) のときだけは全てのフィールドが必須入力となるが、そうでない場合は field1field2 のみ必須となり、 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 哲学に反する点でもあるのだろうか。そもそもとして、このようなことが必要になるのはモデルの設計が悪いとか、コンテキストの使い方を間違っているとか、そういう話なのかもしれないが、そうは言っても現実というものは理想とは程遠いもんである。

トラックバック(0)

トラックバックURL: http://labs.timedia.co.jp/mt/mt-tb.cgi/432

コメントする

このブログ記事について

このページは、1024が2014年7月25日 00:00に書いたブログ記事です。

ひとつ前のブログ記事は「JavaScriptでシェフィを実装する(設計編)」です。

次のブログ記事は「JavaScriptでシェフィを実装する(基礎作成編)」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。