【问题标题】:Identifying conflicting dates on create in rails识别在rails中创建的冲突日期
【发布时间】:2017-11-19 12:38:15
【问题描述】:

制作预订应用程序。如何检查或验证日期,例如 date_startdate_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

查看 - 选择日期

<%= f.label :'date_start:' %>
<%= f.date_field :date_start %>

<%= f.label :'date_end:' %>
<%= f.date_field :date_end %>

样品日期 26 到 27 已经被预订/保留,它必须防止插入 25 到 28,因为 26 到 27 已经被预订。

【问题讨论】:

  • 你的代码有什么问题?
  • @Imran 我希望能够添加验证以检查上述日期之间的冲突。示例日期 26 到 27 已被预订/保留,据说应用程序必须防止插入 25 到 28,因为 26 到 27 已经被预订。
  • 您使用的是什么数据库(如果您想要基于 SQL 的解决方案)?
  • @AndrewMarshall mysql

标签: ruby-on-rails date


【解决方案1】:

型号:

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 结尾

这是rails console 在我尝试创建 (24 nov - 27 nov) 和 (25 nov - 27 nov) 之后的日志,当时有 (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) 开始 (0.6 毫秒)从“预订”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) 提交 => # irb(main):004:0> Reservation.create date_start: Date.parse('24-11-2017'), date_end: Date.parse('27-11-2017') (0.1ms) 开始 (0.2 毫秒)从“预订”WHERE('2017-11-24' date_start)中选择计数(*) (0.2ms) 回滚 => # irb(main):005:0> Reservation.create date_start: Date.parse('25-11-2017'), date_end: Date.parse('26-11-2017') (0.1ms) 开始 (0.3 毫秒)从“预订”WHERE('2017-11-25' date_start)中选择计数(*) (0.1ms) 回滚 => #

如预期的那样有回滚。

【讨论】:

  • 不,它仍然插入为 11 月 25 日至 26 日创建预订的日期,并且同一用户现在将为 11 月 24 日至 27 日创建另一个预订,这可能是一个错误,因为 11 月 25 日至 26 日已被预订,如何检查或验证日期,使其不与其他日期冲突?
【解决方案2】:

您的验证无效,因为您正在检查新的预订日期是否在数据库中已存在的预订日期之间。在您提到的特定情况下,您需要检查现有预订日期是否在新预订日期之间。

问题中提到的示例供参考:

数据库中已经存在预订

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 时。 (你在问题中提到的案例)

案例4

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

【讨论】:

    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2011-12-21
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 2016-08-03
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多