我有两个型号的房子和预订。所有东西都比预订_date验证更好。但是当我尝试在同一个请求中更新或创建多个预订时。验证无法在同一请求参数中检查无效预订。
举个例子,假设预订表是空的。
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
我谷歌近2个小时,找不到任何东西。解决这个问题的最佳方法是什么?
一些资源
答案 0 :(得分:2)
这对我来说只是一个15分钟的快速研究,所以我可能错了,但我相信这是你问题的根本原因:
Accept_nested_attributes_for做什么在底层,它为新的Booking对象调用'build'(此时没有任何验证,对象在内存中创建,没有存储到db)并注册验证并保存挂钩以在父对象时调用对象(House)已保存。因此,根据我的理解,所有创建的对象首先调用所有验证(通过为每个对象调用'valid?'。然后,再次如果我正确,则使用insert_record(记录)保存它们,false)导致save(:validate =&gt; 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(请记住,我们只是在循环中为每个对象调用有效?,稍后将进行保存)。因此,对数据库运行查询的Booking.where(...)在那里找不到它们并且什么都不返回。因此他们都通过有效的?阶段然后保存。
简而言之,以这种方式一起创建的记录不会相互交叉验证(仅针对数据库中以前存在的记录)。因此,你看到的问题。
因此要么一个一个地保存它们,要么在保存之前自己检查同时创建的预订中的日期重叠情况。