Go to list of users who liked
More than 3 years have passed since last update.
Railsのバリデーションは、:on
オプションをつけることで任意のコンテキストのときだけ実行させることができます。
validates :name, presence: true # 常にバリデーションするvalidates :description, presence: true, on: :hoge # context: :hogeのときだけバリデーションする
しかし、context: :hoge
以外のときだけバリデーションしたいときはどうすればいいのでしょうか。:on
で:hoge
以外のコンテキストを全て指定するなどというのは流石にありえませんが、Railsガイドには説明がありません。
そのようにしたい場合は、以下のようにvalidation_context
を参照したlambdaやProcを:unless
に渡して条件を指定すれば実現できます。
validates :name, presence: true # 常にバリデーションするvalidates :description, presence: true, unless: -> { validation_context == :hoge } # context: :hoge以外のときだけバリデーションする
なぜこのような書き方になるのでしょうか。
まず:unless
で指定できるのは、以下のように:on
を:if
に読み替えており:on
と:if
は同等、:unless
は::if
の逆なので:unless
は:on
の逆となるためです。
# https://github.com/rails/rails/blob/5-2-stable/activemodel/lib/active_model/validations.rb#L154def validate(*args, &block) options = args.extract_options! if args.all? { |arg| arg.is_a?(Symbol) } options.each_key do |k| unless VALID_OPTIONS_FOR_VALIDATE.include?(k) raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{VALID_OPTIONS_FOR_VALIDATE.map(&:inspect).join(', ')}. Perhaps you meant to call `validates` instead of `validate`?") end end end if options.key?(:on) options = options.dup options[:on] = Array(options[:on]) options[:if] = Array(options[:if]) options[:if].unshift ->(o) { !(options[:on] & Array(o.validation_context)).empty? } end set_callback(:validate, *args, options, &block)end
またvalidation_context
を参照できるのは、save
する際に呼ばれる以下の処理において、引数から渡ってきた:context
をself.validation_context
にセットしているためです。
# https://github.com/rails/rails/blob/5-2-stable/activemodel/lib/active_model/validations.rb#L336def valid?(context = nil) current_context, self.validation_context = validation_context, context errors.clear run_validations!ensure self.validation_context = current_contextend
Railsでこの時だけ特定のバリデーションを検証したくないときしたこと
Rails のバリデーションを特定のコンテキスト「以外」で実行させる
なお条件付きバリデーションをwith_optionsでグループ化する記法がありますが、ここでも同様に、以下のようにvalidation_context
を参照して特定のコンテキスト以外の条件をグループ化することができます。
with_options unless -> { validation_context == :hoge } |not_hoge| # context: :hoge以外のときだけバリデーションする not_hoge.validates :name, presence: true not_hoge.validates :description, presence: trueend
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme