ruby 如何在Rails中验证日期,使其在今天之后?

d6kp6zgx  于 2023-08-04  发布在  Ruby
关注(0)|答案(6)|浏览(87)

我有一个包含属性的活动记录模型:expiry_date.我如何验证它,使它在今天之后(当时的当前日期)?我是Rails和Ruby的新手,我找不到一个类似的问题来回答这个问题?
我使用Rails 3.1.3和Ruby 1.8.7

hsgswve4

hsgswve41#

您的问题在Rails指南中(几乎)得到了准确的回答。
下面是他们给予的示例代码。这个类验证日期是在 * 过去 *,而你的问题是如何验证日期是在 * 未来 *,但调整它应该很容易:

class Invoice < ActiveRecord::Base
  validate :expiration_date_cannot_be_in_the_past

  def expiration_date_cannot_be_in_the_past
    if expiration_date.present? && expiration_date < Date.today
      errors.add(:expiration_date, "can't be in the past")
    end
  end    
end

字符串

a64a0gku

a64a0gku2#

下面是设置自定义验证器的代码:

#app/validators/not_in_past_validator.rb
class NotInPastValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value.blank?
      record.errors.add attribute, (options[:message] || "can't be blank")
    elsif value <= Time.zone.today
      record.errors.add attribute,
                        (options[:message] || "can't be in the past")
    end
  end
end

字符串
在你的模型中:

validates :signed_date, not_in_past: true

idfiyjo8

idfiyjo83#

最简单有效的解决方案是使用Rails的内置验证。就像这样验证它:

validates :expiry_date, inclusion: { in: (Date.today..Date.today+5.years) }

字符串

2j4z5cfb

2j4z5cfb4#

我接受了@dankohn的回答,并更新为I18 n就绪。我还删除了blank测试,因为这不是该验证器的职责,并且可以通过将presence: true添加到validates调用来轻松启用。
更新后的类,现在命名为in_future,我认为它比not_in_past更好

class InFutureValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.errors.add(attribute, (options[:message] || :in_future)) unless in_future?(value)
  end

  def in_future?(date)
    date.present? && date > Time.zone.today
  end
end

字符串
现在将in_future密钥添加到本地化文件中。
对于errors.messages.in_future下的所有字段,例如荷兰语:

nl:
  errors:
    messages:
      in_future: 'moet in de toekomst zijn'


activerecord.errors.models.MODEL.attributes.FIELD.in_future下的每个字段,例如对于荷兰语Vacancy型号中的end_date

nl:
  activerecord:
    errors:
      models:
        vacancy:
          attributes:
            end_date:
              in_future: 'moet in de toekomst zijn'

x3naxklr

x3naxklr5#

在rails 4+中,DateTime对象有future?past?方法,因此更简单的答案是

class Invoice < ActiveRecord::Base
  validate :expiration_date_cannot_be_in_the_past

  def expiration_date_cannot_be_in_the_past
    if expiration_date.present? && expiration_date.past?
      errors.add(:expiration_date, "can't be in the past")
    end
  end    
end

字符串

camsedfj

camsedfj6#

我从其他帖子中收集了一些东西来得到我的答案,但我认为我的结果可能比创建一个单独的验证器方法或类更直接,我认为我们可以绕过相对简单的验证。

  • 我使用了proc,这样它就可以在运行验证时加载,而不是在加载类时加载。也有一些建议给出了lambda(->(data)),但这要求你在实际上不需要参数时表现得像有一个参数。
  • 对我来说,我不想在没有更新的情况下抛出验证错误,所以我还添加了if: :changed?,这样只有在记录有更新的情况下才会出现验证错误。如果你想处理一个特定的字段,甚至只是时间戳字段,你可以通过组合字段名和changed?- ex来使用rails方法。:my_cool_timestamp_attribute_changed?
  • 错误信息有点不具体,所以它有助于制作一个自定义的。如果不添加消息,它将返回为... is not included in the list
  • 在我的例子中,我只担心更新(而不是初始创建)可能是在过去设置的,所以我有on: :update。rails的默认设置是在创建和更新时进行验证。
validates(
    :my_cool_timestamp_attribute,
    inclusion: {
      in: proc { Time.current.. },
      message: "must be in the future when updating",
      if: :changed?
    },
    on: :update,
  )

字符串

相关问题