【问题标题】:Validating time in rails在 Rails 中验证时间
【发布时间】:2015-08-17 15:14:49
【问题描述】:

我的应用程序有两次用户输入,为了方便用户,我计算了它们之间的时间量。所以用户输入 1:00 AM 作为开始时间,2:00 AM 作为停止时间,它会输出“1 小时”。我有一个辅助方法可以做到这一点,使用宝石进行繁重的工作。时间以 Time 数据类型存储在数据库中,以使其正常工作。

一切正常,现在我想验证用户输入的时间是否有效——但也不需要它。因此,如果用户在这些时间没有输入任何内容,记录仍然会保存 - 但如果用户输入,说“asdfasdf”,我希望触发验证并说这是一个无效时间,而不是默默地不存储时间.

我像这样创建了自己的自定义时间验证:

class TimeValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    Time.parse(value.to_s)
  rescue ArgumentError
    record.errors[attribute] << (options[:message] || "is not a valid time")
  end
end

然后在我的模型中,我正在做:

validates :start_time, time: true
validates :stop_time, time: true

只要确保可以正确解析时间,这就是我想要的,它工作得很好。用户可以输入 14:00、3:00 PM 等……Rails 可以解析它。如果他们输入“asdfasdf”或任何无法解析为有效时间的值,则会通过表单验证错误通知用户并且不会保存记录。

但就该代码而言,如果该值留空,它也会触发验证错误。

同样,我希望它通过 nil 值的验证,但如果存在无法解析的某些值则失败。

我试过了:

validates :start_time, time: true, allow_blank: true

但是“asdfasdf”会通过。我也试过了

Time.parse(value.to_s) unless value.nil?

但同样,这会破坏整个事情并允许无效日期通过。

有什么想法吗?

【问题讨论】:

  • 1) 当您使用 allow_nil 而不是空白时会发生什么? 2)因为你有一个验证器类,也许使用:validates_with(见文档edgeguides.rubyonrails.org/…)我前几天自己调查过,但没有使用它。所以我不确定它是否有帮助。

标签: ruby-on-rails ruby validation ruby-on-rails-4 time


【解决方案1】:

我必须首先承认我不是 Rails/Ruby 专家。

我今天遇到了同样的问题,我想我已经解决了。问题是 Rails 执行类型转换。如果您输入无效参数(例如 starttime="asdf"),则会创建一个虚拟时间对象。当您验证它时,似乎一切都很好,尽管它显然没有。您可以使用:starttime_before_type_cast 访问“真实”参数值。

我相应地调整了 Yule 的代码:

class TimeValidator < ActiveModel::EachValidator

  def validate_each(record, attribute, value)
    return true unless value
    begin
      Time.parse(value.to_s)
    rescue ArgumentError
      y = attribute.to_s
      y.slice! "_before_type_cast"
      record.errors[y] << (options[:message] || "invalid time format entered")
    end
  end

end

模型中的验证应该如下所示:

validates :starttime, presence: true
validates :starttime_before_type_cast, time: true

这种方法的唯一障碍是表单中的字段将包含时间 00:00,而不是验证后的格式错误的值。 IE。用户不会看到他输入的内容以及导致错误消息的原因。

An article about Rails Type Casting

【讨论】:

    【解决方案2】:

    如果你想使用宝石,你可以使用这个。

    这会验证时间和日期。请参阅此处的一些示例:

    validates_datetime :occurred_at
    
    validates_date :date_of_birth, :before => lambda { 18.years.ago },
                                   :before_message => "must be at least 18 years old"
    
    validates_datetime :finish_time, :after => :start_time # Method symbol
    
    validates_date :booked_at, :on => :create, :on_or_after => :today # See Restriction Shorthand.
    
    validates_time :booked_at, :between => ['9:00am', '5:00pm'] # On or after 9:00AM and on or before 5:00PM
    validates_time :booked_at, :between => '9:00am'..'5:00pm' # The same as previous example
    validates_time :booked_at, :between => '9:00am'...'5:00pm' # On or after 9:00AM and strictly before 5:00PM
    
    validates_time :breakfast_time, :on_or_after => '6:00am',
                                    :on_or_after_message => 'must be after opening time',
                                    :before => :lunchtime,
                                    :before_message => 'must be before lunch time'
    

    【讨论】:

      【解决方案3】:

      你快到了,你只需要明确地说 nil 是有效的

      class TimeValidator < ActiveModel::EachValidator
        def validate_each(record, attribute, value)
          return true unless value #nil value is valid
          Time.parse(value.to_s)
        rescue ArgumentError
          record.errors[attribute] << (options[:message] || "is not a valid time")
        end
      end
      

      【讨论】:

      • 这不起作用。 “asdf”的值不会触发上述代码中的验证错误。我不太明白为什么。
      • 我确认该值确实是作为“asdf”发送的,但是在 validate_each 方法中,该值已经在 Rails 堆栈中的某个位置更改为 nil...跨度>
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-25
      • 1970-01-01
      • 1970-01-01
      • 2015-10-25
      相关资源
      最近更新 更多