【问题标题】:Validating datetime entries in a model验证模型中的日期时间条目
【发布时间】:2018-07-21 16:36:59
【问题描述】:

我正在使用 Rails 中的数据库和模型,并且我有一个看起来像这样的“创建游览”迁移

class CreateTours < ActiveRecord::Migration[5.2]
  def change
    create_table :tours do |t|
      t.string :name
      t.integer :price
      t.datetime :starts_at
      t.datetime :ends_at
    end
  end
end

我添加了一个模型Tour

class Tour < ApplicationRecord
  has_many :bookings, dependent: :destroy

  validates :name, presence: true,
                   uniqueness: { case_sensitive: false }
  validates :starts_at, presence: true
  validates :ends_at, presence: true
  validates :price, presence: true,
                         numericality: { greater_than: 0 }

  validate :end_time_is_valid

  def end_time_is_valid
    error_msg = 'Trip cannot ends before it began'
    errors.add(:ends_at, error_msg) if ends_at < starts_at
  end
end

我添加了 RSpec

RSpec.describe Tour do
  subject do
    described_class
      .create(
        name: 'Tour 1',
        starts_at: Time.zone.now,
        ends_at: Time.zone.now + 7200,
        price: 200
      )
  end

  let(:invalid_flight) do
    described_class.create(
      name: 'Tour 2',
      starts_at: Time.zone.now,
      ends_at: Time.zone.now - 7200,
      price: 200
    )
  end

  it { is_expected.to validate_presence_of(:name) }
  it { is_expected.to validate_presence_of(:starts_at) }
  it { is_expected.to validate_presence_of(:ends_at) }
  it { is_expected.to validate_presence_of(:price) }

  it { is_expected.to have_many(:bookings) }
end

现在,我遇到了类似的错误

Flight should validate that :starts_at cannot be empty/falsy
     Failure/Error: errors.add(:ends_at, error_msg) if ends_at < starts_at

     ArgumentError:
       comparison of ActiveSupport::TimeWithZone with nil failed
     # ./app/models/tour.rb:18:in `<'
     # ./app/models/tour.rb:18:in `end_time_is_valid'
     # ./spec/models/tour_spec.rb:22:in `block (2 levels) in <main>'

我要添加的是验证结束游览时间不能早于游览开始时间。

但是自定义验证失败,我不知道为什么。

我正在使用 Rails,但不知道该怎么做。

我正在使用shoulda-matchers 进行测试。

一些简单的模型,例如User,只有简单的name 和email 验证正在通过(没有自定义验证)。

如何验证这一点?我也应该在这里使用numericality 吗?

【问题讨论】:

    标签: ruby-on-rails ruby validation model


    【解决方案1】:

    当starts_at 为空白/nil 时,您的验证仍会被调用,即使您已经定义了presence 验证:验证没有层次结构,因此一个失败不会导致其他验证被跳过。

    因此,您的验证方法应该跳过检查任一值是否为空 - 留下 presence 验证来记录错误。

    def end_time_is_valid
      return if starts_at.blank? || ends_at.blank?
    
      error_msg = 'Trip cannot ends before it began'
      errors.add(:ends_at, error_msg) if ends_at < starts_at
    end
    

    【讨论】:

    • 我会试试这个,看看它会返回什么。我认为在模型中指定它们时验证的顺序并不重要。
    • 是的,成功了!谢谢。我想我假设如果存在失败,将自动跳过其他验证,因为不会进行任何数据库条目。
    猜你喜欢
    • 2016-09-04
    • 2016-04-26
    • 1970-01-01
    • 2019-04-21
    • 2014-03-13
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    相关资源
    最近更新 更多