【问题标题】:Avoid double bookings for a minibus reservation system避免重复预订小巴预订系统
【发布时间】:2018-08-18 15:26:11
【问题描述】:

我正在尝试建立一个客户可以预订小巴的预订系统。我已经能够获取所有数据,以便可以进行预订。

我试图避免其他用户在同一天预订小巴。我不确定如何像新的 ruby​​ on rails 那样去做。

在我的reservation.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

我会使用验证来停止重复预订吗? 会不会像在我的预订中一样。rb

validates :vehicle_id, :startDate, :uniqueness => { :message => " minibus already reserved"}

虽然以上只允许预订车辆。

任何帮助将不胜感激!

【问题讨论】:

  • start_date 意味着还有一个end_date 。这是否意味着您的预订不存储特定日期,而是存储日期范围?
  • 是的,我应该提到。它存储开始和结束日期

标签: ruby-on-rails ruby


【解决方案1】:

正如您已经发现的那样,您不能使用 Rails 的内置唯一性验证器来验证两个范围不重叠。

您必须构建一个自定义验证来检查这一点。检查两个时间或日期范围AB 是否重叠的条件非常简单。看看这张图片。

A:      |-----|
B1:   |-----|
B2:   |---------|
B3:       |-----|
C1: |-|
C2:             |-|

AB 如果B.start < A.end && B.end > A.start 重叠

将以下内容添加到您的模型中:

# 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 约定。
  • 此外,您可能需要&lt;=&gt;=(而不是&lt;&gt;),具体取决于您对开始和结束的定义。
  • 将条件移动到命名范围是个好主意,并且会提高可读性

【讨论】:

  • 我不断收到“您需要为validates :reservation_must_not_overlap 提供至少一个验证”的消息,我该如何克服这个问题?我已经根据它们应该如何更改了字段。即我将 end_date 命名为 endDate
  • 我已经解决了上述问题,它必须是验证而不是验证。正如stackoverflow.com/questions/25954023/… 中提到的,我现在收到.where(vehicle_id: reservation_id) 的reservation_id 错误。为什么会这样?
  • 我修正了validate :reservations_must_not_overlap的错字,条件必须改为.where(vehicle_id: vehicle_id)reservation_id 在这种情况下没有任何意义,对此感到抱歉。
【解决方案2】:

你会想要使用 uniqueness 验证器,但你已经在使用 scope 选项。

他们在该页面上提供的示例与您的用例非常相似:

class Holiday < ApplicationRecord
  validates :name, uniqueness: { scope: :year,
    message: "should happen once per year" }
end

至于您应该验证哪一列,这并不重要。由于唯一性范围将是所有三列,它可以是其中任何一个:

validates :vehicle_id, uniqueness, { scope: [:startDate, user_id], message: "your message" }

您还应该按照here 的描述向数据库添加索引(顺便说一下,这个问题与您的问题非常相似)。

【讨论】:

  • 您好感谢以上我使用了以下验证。 validates :vehicle_id, uniqueness: {scope: [:startDate, :endDate], :message =&gt; " already booked"} 如果开始日期和结束日期相同,则可以正常工作。假设开始日期是 3 月 10 日到 3 月 12 日,我仍然可以从 3 月 10 日到 11 日预订同一辆车。我该如何避免这种情况?
  • 您正在寻找范围重叠验证,唯一性验证无法满足您的所有需求。据我所知,Rails 中还没有任何内容。有一个古老的“range_validator” gem,但它可能与现代 Rails 不兼容(尽管值得一试),但可以作为您提出自己的自定义验证的起点。
猜你喜欢
  • 2012-03-09
  • 2019-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-03
  • 2012-05-05
  • 2012-03-27
  • 2020-07-29
相关资源
最近更新 更多