Rails Active Record嵌套属性验证位于同一请求中

时间:2013-02-27 13:49:35

标签: ruby-on-rails ruby-on-rails-3 activerecord nested-attributes rails-activerecord

我有两个型号的房子和预订。所有东西都比预订_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个小时,找不到任何东西。解决这个问题的最佳方法是什么?

一些资源

1 个答案:

答案 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_associationhttp://apidock.com/rails/ActiveRecord/Associations/HasAndBelongsToManyAssociation/insert_record

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

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

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