0

我有两个样板房和预订。预订日期验证一切正常。但是当我尝试在同一个请求中更新或创建多个预订时。验证无法检查同一请求参数中的无效预订。

举个例子,假设预订表是空的。

params = { :house => {
  :title => 'joe', :booking_attributes => [
    { :start_date => '2012-01-01', :finish_date => '2012-01-30 },
    { :start_date => '2012-01-15', :finish_date => '2012-02-15 }
  ]
}}

第二次预订也保存,但它的 start_date 在第一次预订间隔之间。当我一一保存它们时,验证工作。

class House < ActiveRecord::Base
  attr_accessible :title, :booking_attributes
  has_many :booking
  accepts_nested_attributes_for :booking, reject_if: :all_blank, allow_destroy: true
end

class Booking < ActiveRecord::Base
  belongs_to :house
  attr_accessible :start_date, :finish_date

  validate :booking_date
  def booking_date

    # Validate start_date
    if Booking.where('start_date <= ? AND finish_date >= ? AND house_id = ?',
      self.start_date, self.start_date, self.house_id).exists?
      errors.add(:start_date, 'There is an other booking for this interval')
    end

    # Validate finish_date
    if Booking.where('start_date <= ? AND finish_date >= ? AND house_id = ?',
      self.finish_date, self.finish_date, self.house_id).exists?
      errors.add(:finish_date, 'There is an other booking for this interval')
    end
  end
end

我google了将近2个小时,找不到任何东西。解决此问题的最佳方法是什么?

一些资源

4

1 回答 1

2

这只是我 15 分钟的快速研究,所以我可能错了,但我相信这是您问题的根本原因:

accept_nested_attributes_for 在幕后做了什么,它为新的 Booking 对象调用“构建”(此时没有验证任何内容,对象是在内存中创建的,而不是存储到数据库中)并注册验证和保存挂钩以在父对象(House ) 被保存。因此,据我所知,首先为所有创建的对象调用所有验证(通过为每个对象调用“有效?”。然后,如果我做对了,它们会使用 insert_record(record,false) 保存(:validate => false),因此不会第二次调用验证。

您可以查看这些页面中的来源:http ://apidock.com/rails/v3.2.8/ActiveRecord/AutosaveAssociation/save_collection_association,http : //apidock.com/rails/ActiveRecord/Associations/HasAndBelongsToManyAssociation/insert_record

您验证调用 Booking.where(...) 来查找重叠的日期范围。此时,新创建的 Booking 对象仍然只在内存中,没有保存到 db 中(记住,我们只是为循环中的每个对象调用 valid?,稍后将完成保存)。因此,对数据库运行查询的 Booking.where(...) 在那里找不到它们并且什么也不返回。因此他们都通过有效?阶段然后保存。

简而言之,以这种方式一起创建的记录不会相互交叉验证(仅针对数据库中先前存在的记录)。因此,您看到的问题。

因此,要么一个一个地保存它们,要么在保存之前在同时创建的预订中检查此类日期重叠的情况。

于 2013-02-28T00:37:17.653 回答