避免对小巴预订系统进行双重预订
我正在尝试建立一个客户可以预订小巴的预订系统。 我已经能够获得所有数据,因此可以预订。
我试图避免其他用户在同一天预订小巴。 我不确定如何在轨道上使用ruby。
在我的预订.rb我有
belongs_to :vehicle belongs_to :user
在我的user.rb和vehicle.rb中我有
has_many :reservation
在我的预订控制器中,我有
def new @vehicle = Vehicle.find(params[:vehicle_id]) @reservation = Reservation.new(user_id: User.find(session[:user_id]).id) @reservation.vehicle_id = @vehicle.id end
我会使用validation来停止双重预订吗? 会不会像我的预订一样.rb
validates :vehicle_id, :startDate, :uniqueness => { :message => " minibus already reserved"}
虽然以上只允许预留车辆。
任何帮助都感激不尽!
正如您已经发现的那样,您无法使用Rails的内置唯一性validation器来validation两个范围不重叠。
您必须构建自定义validation才能检查此问题。 检查两个时间或日期范围A
和B
重叠的条件非常简单。 看看这张图片。
A: |-----| B1: |-----| B2: |---------| B3: |-----| C1: |-| C2: |-|
如果B.start < A.end && B.end > A.start
则A
和B
重叠
将以下内容添加到您的模型中:
# app/models/reservation.rb validate :reservations_must_not_overlap private def reservations_must_not_overlap return if self .class .where.not(id: id) .where(vehicle_id: vehicle_id) .where('start_date < ? AND end_date > ?', end_date, start_date) .none? errors.add(:base, 'Overlapping reservation exists') end
一些说明:
- 您可能需要调整数据库列和属性名称的命名,因为我不确定它是否只是一个拼写错误,或者您是否使用不遵循Ruby约定的名称。
- 此外,您可能需要
<=
和>=
(而不是<
和>
),具体取决于您对start和end的定义。 - 将条件移动到命名范围是一个好主意,并将提高可读性
您将要使用您已经在做的唯一性validation器,但使用scope
选项。
他们在该页面上给出的示例与您的用例非常相似:
class Holiday < ApplicationRecord validates :name, uniqueness: { scope: :year, message: "should happen once per year" } end
至于你应该validation哪一列,它并不重要。 由于唯一性范围将是所有三列,因此它可以是以下任何一列:
validates :vehicle_id, uniqueness, { scope: [:startDate, user_id], message: "your message" }
您还应该按照此处所述向数据库添加索引(顺便提一下,这个问题与您的问题非常相似)。