【问题标题】:Rails validation method comparing two fields?比较两个字段的Rails验证方法?
【发布时间】:2011-06-19 08:34:48
【问题描述】:

我的模型有两个字段,作为验证的一部分,我想将它们相互比较。我想确定 end_time 在 start_time 之后。我写了一个验证方法来比较它们,但我一定做错了什么,因为值总是为零。有人可以帮忙吗?

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 为零。我以为我在遵循我找到的许多示例,但显然不是。我错过了什么?

谢谢。

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3


    【解决方案1】:

    您需要自己检查是否存在(如果不存在则跳过验证步骤)。

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

    打印“必须是有效的日期/时间”或“开始时间必须早于结束时间”。

    另类

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

    如果未设置 start_time 或 end_time,则打印“开始时间必须是有效的日期/时间”和“开始时间必须早于结束时间”。

    个人偏好第一,因为它只显示用户做错了什么。后者就像许多网站一样,只是将 20 行错误文本加载给用户,只是因为程序员认为看到每个验证结果会很好。糟糕的用户体验。

    【讨论】:

    • 是的,试过了,它总是返回。不会失败,所以很好,但也不会比较时代......
    • 添加了“检查”日期的选项。您必须确保设置了 start_time 和 end_time,否则验证当然不会运行(尽管存在检查应该会阻止保存记录)。
    • 这避免了 nil 问题,但也阻止了添加有效日期 - 我现在总是收到“开始时间必须在结束时间之前”消息。
    【解决方案2】:

    干净整洁(并且在控制之下?)

    我觉得这是最清楚的阅读:

    在您的模型中

    # ...
    
    validates_presence_of :start_time, :end_time
    
    validate :end_time_is_after_start_time
    
    # ... 
    
    #######
    private
    #######
    
    def end_time_is_after_start_time
      return if end_time.blank? || start_time.blank?
    
      if end_time < start_time
        errors.add(:end_time, "cannot be before the start time") 
      end 
    end
    

    【讨论】:

      【解决方案3】:

      我最好的猜测是你需要你的方法看起来像这样:

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

      (另外,请注意&lt; 而不是&gt;(或更改为if&gt;=

      如果这不起作用,那么您还应该检查 start_timeend_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

      【讨论】:

      • 我希望添加“self”会有所作为,但我得到了同样的错误。到目前为止,start_time 和 end_time 一直运行良好,只是您可以将结束放在开始之前。我想我会暂时放弃。谢谢。
      • 然后我开始怀疑控制器中 start_time 和 end_time 的设置方式。你为他们使用了什么样的表单元素?
      • start_time 和 end_time 分别由 f.datetime_select 设置。我不知道为什么这些值无法验证 - 它们肯定会在以后出现。我是 Rails 新手,我有什么误解吗?
      • 就是这样!问题出在 f.datetime_select 上。我将表单更改为仅使用文本字段进行输入,并且值用于验证。我不明白的是为什么其余代码适用于 f.datetime_select?在这种情况下,何时设置 start_time 和 end_time?感谢您的帮助。
      • 阅读这个 - guides.rubyonrails.org/… - 它可能足以让您重新使用 datetime_select。问题是活动记录必须从 3 个单独的表单组件构造日期,因此日期不会作为参数哈希中的单个项目返回。
      【解决方案4】:

      您可以使用 validates_timeliness gem https://github.com/adzap/validates_timeliness

      【讨论】:

        【解决方案5】:

        start_time.to_i &lt; end_time.to_i应该修复它。您正在尝试比较日期时间,但由于某种原因它不能,因此在比较之前将它们转换为 int。

        【讨论】:

          【解决方案6】:

          Ruby on Rails 7.0 像这样支持validates_comparison_of

          validates :start_time, comparison: { less_than: :end_date }
          

          【讨论】:

            猜你喜欢
            • 2015-07-08
            • 2018-02-21
            • 2013-01-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-02
            相关资源
            最近更新 更多