识别在rails中创建的冲突日期

时间:2017-11-19 12:38:16

标签: ruby-on-rails date

预订应用。如何查看或验证日期,例如SELECTdate_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个。

3 个答案:

答案 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

您需要检查以下情况:

<强>符号

  • R1 是数据库中已存在的预订
  • R2 是用户尝试添加的新预订。
  • | 表示开始日期和结束日期

<强>案例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)

  • 您的预订表上会有很多日期。例如:

    • 预订一:7.days.from_now~6.days.from_now
    • 预订二:3.days.from_now~1.days.from_now
  • 这意味着您必须按每个范围识别保留日期。

    • 最初:1~3,6~7
  • 我使用哈希来索引保留日期,如下所示:

    • 暂无日期(从现在开始):1,2,3,6,7
    • 另外,您可以通过仅搜索(或确定)目标date_start和date_end或有效预订来创建有效的索引

型号:

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