0

私は2つのモデルの家と予約を持っています。booking_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 }
  ]
}}

2番目の予約も保存されますが、そのstart_dateは最初の予約間隔の間にあります。それらを1つずつ保存すると、検証が機能します。

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時間近くグーグルで検索しましたが、何も見つかりませんでした。この問題を解決するための最良のアプローチは何ですか?

いくつかのリソース

4

1 に答える 1

2

これは私の側での15分間の簡単な調査だったので、間違っているかもしれませんが、これがあなたの問題の根本的な原因であると信じています。

accepts_nested_attributes_forが内部で行うことは、新しいBookingオブジェクトに対して「build」を呼び出し(この時点では何も検証されません。オブジェクトはメモリに作成され、dbに保存されません)、検証を登録し、親オブジェクト(House )が保存されます。したがって、私の理解では、すべての検証は最初に作成されたすべてのオブジェクトに対して呼び出されます(それぞれに対して「valid?」を呼び出すことによって。次に、正しく取得した場合は、insert_record(record、false)を使用して保存されます。 (:validate => false)、したがって、検証は2回目に呼び出されません。

これらのページ内のソースを見ることができます:http://apidock.com/rails/v3.2.8/ActiveRecord/AutosaveAssociation/save_collection_association、http//apidock.com/rails/ActiveRecord/Associations/HasAndBelongsToManyAssociation/insert_record

検証では、Booking.where(...)を呼び出して、重複する日付範囲を見つけます。この時点で、新しく作成された予約オブジェクトはまだメモリ内にあり、データベースには保存されていません(ループ内の各オブジェクトに対して、有効と呼んでいることを思い出してください。保存は後で行われます)。したがって、DBに対してクエリを実行するBooking.where(...)は、DBを検出せず、何も返しません。したがって、それらはすべて有効に合格しますか?ステージして保存します。

一言で言えば、そのような方法で一緒に作成されたレコードは、相互に相互検証されません(データベース内の既存のレコードに対してのみ)。したがって、あなたが見る問題。

したがって、それらを1つずつ保存するか、保存する前に、同時に作成された予約の中でそのような日付が重複するケースを自分で確認してください。

于 2013-02-28T00:37:17.653 に答える