我有几个带有日期属性的模型,对于每个模型,我想根据给定范围验证这些日期。一个基本的例子是:
validates_inclusion_of :dated_on, :in => Date.new(2000,1,1)..Date(2020,1,1)
理想情况下,我想在运行时评估日期范围,使用与named_scope
使用类似的方法,例如:
validates_inclusion_of :dated_on, :in => lambda {{ (Date.today - 2.years)..(Date.today + 2.years)}}
上述方法当然不起作用,那么实现相同结果的最佳方法是什么?
答案 0 :(得分:13)
您可以使用date validator:
validates :dated_on, :date => {:after => Proc.new { Time.now + 2.years },
:before => Proc.new { Time.now - 2.years } }
答案 1 :(得分:7)
如果每个类的验证相同,答案非常简单:将验证方法放入模块并将其混合到每个模型中,然后使用validate
添加验证:
# in lib/validates_dated_on_around_now
module ValidatesDatedOnAroundNow
protected
def validate_dated_around_now
# make sure dated_on isn't more than five years in the past or future
self.errors.add(:dated_on, "is not valid") unless ((5.years.ago)..(5.years.from_now)).include?(self.dated_on)
end
end
class FirstModel
include ValidatesDatedOnAroundNow
validate :validate_dated_around_now
end
class SecondModel
include ValidatesDatedOnAroundNow
validate :validate_dated_around_now
end
如果你想为每个模型设置不同的范围,你可能想要更像这样的东西:
module ValidatesDateOnWithin
def validates_dated_on_within(&range_lambda)
validates_each :dated_on do |record, attr, value|
range = range_lambda.call
record.errors.add(attr_name, :inclusion, :value => value) unless range.include?(value)
end
end
end
class FirstModel
extend ValidatesDatedOnWithin
validates_dated_on_within { ((5.years.ago)..(5.years.from_now)) }
end
class SecondModel
extend ValidatesDatedOnWithin
validates_dated_on_within { ((2.years.ago)..(2.years.from_now)) }
end
答案 2 :(得分:3)
validates :future_date, inclusion: { in: ->(g){ (Date.tomorrow..Float::INFINITY) }
答案 3 :(得分:1)
另一种解决方案是依赖validates_inclusion_of
仅需要响应:in
的{{1}}对象这一事实。建立延迟评估范围如下:
include?
答案 4 :(得分:0)
问问自己是否需要在运行时评估范围。如果价格是复杂的,那么优秀的开发人员并不总是追求正确性。
我想要理智地检查日期是否合理,即从现在开始的几年内。如果事实证明在今天或两周前的几年范围内并不重要,我的服务器进程可能在几年内仍然无法运行。最后,我认为更简单的解决方案(只是一个直接的包含:in => rational_date_range)比正确但更复杂的解决方案更可取。
那就是说,我喜欢James A. Rosen的DelayedEvalRange解决方案。如果你的范围只有几天,或者由于某些其他原因,正确性很重要,我会继续这样做。
答案 5 :(得分:0)
对我来说最简单的解决方案是:
validate :validate_dob
def validate_dob
unless age_range.cover?(dob.present? && dob.to_date)
errors.add(:dob, "must be between %s and %s" % age_range.minmax)
end
end
但是,如果您要删除重复项,我建议您将其移至your own validator。
是的,我想要运行时执行,因为我的代码将运行几年,经过一年多的时间我没有部署,我当然不想要再次提出这个项目。
答案 6 :(得分:0)
最简单且最有效的解决方案是使用Rails的内置验证。只需验证它:
validates :dated_on, inclusion: { in: (Date.new(2000,1,1)..Date(2020,1,1)) }
如果您需要验证状态,只需添加另一个验证:
validates :occurred_at, presence: true, inclusion: { in: (Date.new(2000,1,1)..Date(2020,1,1)) }
请记住,您始终可以使用1.day.ago
或1.year.from_now
等帮助程序来定义范围。