预订应用。如何查看或验证日期,例如SELECT
和date_start
的值为
date_end
我将创建另一个具有这些起始和结束日期值但仍与其他值冲突的预留。如何查看有冲突的日期?
date_start date_end
26-11-2017 27-11-2017
用于验证日期之间的日期
模型
date_start date_end
25-11-2017 28-11-2017
查看 - 选择日期
validate :no_reservation_overlap
scope :overlapping, ->(period_start, period_end) do
where "((date_start <= ?) and (date_end >= ?))", period_end, period_start
end
private
def no_reservation_overlap
if (Reservation.overlapping(date_start, date_end).any?)
errors.add(:date_end, 'it overlaps another reservation')
end
end
示例日期26到27已经预订/保留,因为它必须阻止插入25到28,因为已经预订了26到27个。
答案 0 :(得分:4)
型号:
class Reservation < ApplicationRecord
validate :overlapping
private
def overlapping
if Reservation.where('? < date_end and ? > date_start', self.date_start, self.date_end).any?
errors.add(:date_end, 'it overlaps another')
end
end
架构:
create_table "reservations", force: :cascade do |t| t.date "date_start" t.date "date_end" t.datetime "created_at", null: false t.datetime "updated_at", null: false end
在我尝试创建(24 nov - 27 nov)和(25 nov - 27 nov)时,有rails console
日志(25 nov - 26 nov)
irb(main):003:0> Reservation.create date_start: Date.parse('25-11-2017'), date_end: Date.parse('26-11-2017') (0.2ms) BEGIN (0.6ms) SELECT COUNT(*) FROM "reservations" WHERE ('2017-11-25' date_start) SQL (0.6ms) INSERT INTO "reservations" ("date_start", "date_end", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["date_start", "2017-11-25"], ["date_end", "2017-11-26"], ["created_at", "2017-11-21 13:23:05.192276"], ["updated_at", "2017-11-21 13:23:05.192276"]] (10.7ms) COMMIT => # irb(main):004:0> Reservation.create date_start: Date.parse('24-11-2017'), date_end: Date.parse('27-11-2017') (0.1ms) BEGIN (0.2ms) SELECT COUNT(*) FROM "reservations" WHERE ('2017-11-24' date_start) (0.2ms) ROLLBACK => # irb(main):005:0> Reservation.create date_start: Date.parse('25-11-2017'), date_end: Date.parse('26-11-2017') (0.1ms) BEGIN (0.3ms) SELECT COUNT(*) FROM "reservations" WHERE ('2017-11-25' date_start) (0.1ms) ROLLBACK => #
正如预期的那样有回滚。
答案 1 :(得分:4)
您的验证无效,因为您正在检查新预订日期是否已存在于数据库中的预留日期之间。在您提到的具体情况中,您需要检查现有的预订日期是否在新预订日期的日期之间。
问题中提到的示例供参考:
数据库中已有预约
date_start date_end
26-11-2017 27-11-2017
新预订:
date_start date_end
25-11-2017 28-11-2017
您需要检查以下情况:
<强>符号强>:
<强>案例1 强>
|------R1------| ____|------R2------|
当R1在R2之前开始和结束时
<强>情况2 强>
______|------R1------| |------R2------|______
当R2在R1之前开始和结束时
<强>情形3 强>
___|------R1------|___ |---------R2---------|
当R2包含R1时。 (你在问题中提到过的案例)
<强> CASE4 强>
|---------R1---------| __|------R2------|___
当R1包含R2时。 (这是您在重叠范围内)所涵盖的唯一案例
免责声明:以下范围未经测试,可能存在一些问题。 (您可以通过覆盖上述所有情况轻松编写SQL查询)
scope :overlapping, ->(period_start, period_end) do
where(
"(:period_start <= date_start AND :period_end < date_end AND :period_start > :period_end) OR
(:period_start >= date_start AND :period_end > date_end AND :period_start < date_end) OR
(:period_start < date_start AND :period_end >= date_end) OR
(:period_start >= date_start AND :period_end <= date_end)",period_start: period_start, period_end: period_end)
end
答案 2 :(得分:3)
您的预订表上会有很多日期。例如:
这意味着您必须按每个范围识别保留日期。
我使用哈希来索引保留日期,如下所示:
型号:
class Reservation < ApplicationRecord
validate :exclusive_reservation?
def exclusive_reservation?
result = true
reserved = {}
Reservation.pluck(:date_start, :date_end).each do |date_range|
(date_range.first..date_range.second).each do |date|
reserved[date] = true
end
end
if reserved.has_key? self.date_start
errors.add(:date_start, 'it overlaps another reservation')
result = false
end
if reserved.has_key? self.date_end
errors.add(:date_end, 'it overlaps another reservation')
result = false
end
result
end
end