如何针对数据库记录验证输入以避免重叠?

时间:2019-04-25 19:07:23

标签: ruby-on-rails

使用Ruby on Rails开发约会管理应用程序,并尝试实现重叠验证。约会有开始和结束时间(不是DateTime格式,只是纯整数)

试图使用Ranges,但是没有用

期望实现以下目标:

数据库现有记录:

[{id:1, start_time:0; end_time:10}, {id:2, start_time:20, end_time:40}]

应该验证一个新的约会对象,以确保它不与其他约会重叠,即

{id:15, start_time:11, end_time:19}应该成功保存

{id:16, start_time:1, end_time:9}不应该保存(与另一个约会(id 1)重叠)

2 个答案:

答案 0 :(得分:0)

您可以编写自定义验证。您可以使用validates来代替validate。不过,您将要使用日期。使用纯整数,除非您每天要删除所有记录(您不想这样做),否则您将只能处理一天。 def中的伪代码。

validate :no_overlap, on: :save

def no_overlap
  # iterate through appointments on that date
  # check for the overlap
  # if overlap exists
  # self.errors.add("Overlaps with existing appointment!")
end

答案 1 :(得分:0)

首先将这些列更改为日期时间或时间类型,以便您可以实际使用数据库日期功能。当数据库实际上可以正确表示时间/日期时,为什么要使用整数?

SQL有一个OVERLAPS关键字,可用于检查两个时间戳之间的重叠:

SELECT  "appointments".* FROM "appointments" 
WHERE ((start_time, end_time) OVERLAPS (a, b)) 

Postgres支持它。作为农民数据库的MySQL需要a hacky workaround

您可以通过以下方式创建“范围”:

class Appointment < ApplicationRecord
  def self.overlapping(range)
    self.where('(?,?) OVERLAPS (starts_at, ends_at)', range.begin, range.end)
  end
end

然后您可以在custom validation中使用范围:

class Appointment < ApplicationRecord
  validates :time_available
  def self.overlapping(range)
    self.where('(?,?) OVERLAPS (starts_at, ends_at)', range.begin, range.end)
  end

  def time_available
    if self.class.overlapping(start_time..end_time).exists?
      errors.add(:base, "time is not available") 
    end
  end
end