Rails验证日期范围的唯一性

时间:2013-04-27 13:01:29

标签: ruby-on-rails validation

我的申请涉及员工的缺勤记录。

我需要确保每条记录的开始和结束日期不重叠。

因此,例如,如果我输入了今天开始并明天结束的缺席记录,则不应该以任何方式在该日期范围内输入另一个记录。所以我不能制作一个在今天前一天开始,然后在后天或之后的任何日期结束。

简而言之,我需要使日期范围独一无二。

实现这一目标的最佳方法是什么?

模型类中涉及遍历所有记录的自定义验证器需要很长时间才能完成,而且我没有找到任何解决此问题的宝石。我也没有找到任何简单的方法来确定模型中的唯一性。我很难过:/

谢谢你的时间!

编辑:

class Absence < ActiveRecord::Base
attr_accessible :date, :date_ended, :status, :reason, :form, :user_id, :tempuser, :company_id
belongs_to :user
default_scope { where(company_id: Company.current_id) }

validates :date, :date_ended, :status, :reason, :form, :user_id, presence: true 
validates_numericality_of :user_id, :only_integer => true, :message => "can only be whole number."
end

5 个答案:

答案 0 :(得分:18)

我用这些:

  scope :overlaps, ->(start_date, end_date) do
    where "(DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", end_date, start_date
  end

  def overlaps?
    overlaps.exists?
  end

  # Others are models to be compared with your current model
  # you can get these with a where for example
  def overlaps
    siblings.overlaps start_date, end_date
  end

  validate :not_overlap

  def not_overlap
    errors.add(:key, 'message') if overlaps?
  end

  # -1 is when you have a nil id, so you will get all persisted user absences
  # I think -1 could be omitted, but did not work for me, as far as I remember
  def siblings
    user.absences.where('id != ?', id || -1)
  end

来源:https://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails

答案 1 :(得分:8)

作为对已接受答案的修改,这里是一个重叠范围,适用于不理解DATEDIFF的数据库

  scope :overlaps, ->(start_date, end_date) do
    where "((start_date <= ?) and (end_date >= ?))", end_date, start_date
  end

这借鉴了Determine Whether Two Date Ranges Overlap

的解决方案

答案 2 :(得分:8)

使用gem validates_overlap

gem 'validates_overlap'

例如,如果您的模型名为Meetingstart_dateend_date字段类型为date,则可以轻松验证它们是否重叠。

class Meeting < ActiveRecord::Base
  validates :start_date, :end_date, overlap: true 
end

另一个更现实的例子,比如Meeting belongs_to a User,您可以将其范围化,因此它只会验证特定用户的会议。

class Meeting < ActiveRecord::Base
  belongs_to User
  validates :start_date, :end_date, overlap: { scope: 'user_id',
                                             message_content: 'overlaps with Users other meetings.' }
end

答案 3 :(得分:1)

有一个名为validates_overlap的宝石,可让您轻松验证日期范围重叠。您还可以在验证中使用范围。

答案 4 :(得分:1)

虽然juanpastas解决方案是正确的,但它对创建记录有效,但可能导致对更新的错误否定验证。

如果您需要编辑现有记录,请说范围是2014-03-13..2014-06-12并且您想将其缩小到2014-03-13..2014-04-12,你' ll会出现重叠错误,因为它正在检查AGAINST本身。

  def siblings
    Absence_users.where('user_id = ? AND id != ?', user_id, self)
  end

将消除这个缺点。 (Dave T的加法也应该遵循,与DB无关。)