Techioz Blog

Railsの2つのフィールドを比較する検証方法は?

概要

私のモデルには、検証の一環として相互に比較したい 2 つのフィールドがあります。 end_time が start_time より後であることを確認したいです。それらを比較するための検証メソッドを作成しましたが、値は常に nil であるため、何か間違ったことをしているに違いありません。誰か助けてくれませんか?

class LogEntry < ActiveRecord::Base
  validates :start_time, :presence => { :message => "must be a valid date/time" }
  validates :end_time, :presence => {:message => "must be a valid date/time"}
  validate :start_must_be_before_end_time

  def start_must_be_before_end_time
    errors.add(:start_time, "must be before end time") unless
       start_time > end_time
  end 
end

エラーが発生します

undefined method `>' for nil:NilClass

したがって、start_time および/または end_time は nil です。見つけた多くの例に従っていると思っていましたが、どうやらそうではないようです。私には何が欠けているのでしょうか?

ありがとう。

解決策

私の推測では、メソッドを次のようにする必要があると思います。

private

def start_must_be_before_end_time
    errors.add(:start_time, "must be before end time") unless
        start_time < end_time
end 

(また、> ではなく < に注意してください (または if と >= に変更してください)

これが機能しない場合は、start_time と end_time がコントローラーで正しく定義されていることも確認する必要があります。時間が複数のフォーム要素にわたって作成されると、おかしなことが起こる可能性があります。

Rails 7 ComparisonValidator を使用する場合

Rails 7 には ComparisonValidator が追加されており、次のように便利なメソッド validates_comparison_of を使用できるようになります。

class LogEntry < ActiveRecord::Base
  validates_comparison_of :start_time, less_than: :end_time
  # OR
  validates_comparison_of :end_time, greater_than: :start_time
end

詳細はこちら: https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_comparison_of