ruby-on-rails - 验证模型中的日期时间条目

标签 ruby-on-rails ruby validation model

我正在 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,只有简单的nameemail验证正在通过(没有自定义验证)。

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

最佳答案

starts_at 为空/nil 时,即使您已经定义了 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

关于ruby-on-rails - 验证模型中的日期时间条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51458114/

相关文章:

ruby-on-rails - Rake:记录任何正在执行的任务

ruby-on-rails - 为什么可枚举方法在某些环境中有效而在其他环境中无效?

ruby-on-rails - Sidekiq 幂等性、N+1 查询和死锁

validation - {[A-Z] [a-z][0-9]} 文本输入的 QLineEdit 验证

php - 使用 CodeIgniter 表单验证的自定义错误消息

javascript - 我可以在 asp.net MVC 中实现任何 Yahoo YUI 验证框架吗?

ruby-on-rails - Rails2.3.8 : How do I run a test using the dev environment? ruby

ruby-on-rails - 在 rails 中持久化内存缓存 session

ruby-on-rails - 测试设计 - Capybara::ElementNotFound:无法找到 xpath "/html"

ruby - 何时在 Ruby 中使用 Kernel#gsub?