在Rails中,我如何验证_uniqueness_of:字段,范围为最近6个月

时间:2009-06-08 20:03:00

标签: ruby-on-rails validation

第一项
我希望在将字段保存到数据库之前验证字段以确保它是唯一的(在过去6个月内)。

我在想我应该使用validates_uniqueness_of:field,case_sensitive => false,Scope => ...

对于我的应用程序,它只需要是唯一的,如果它在6个月前使用过。

想把它与created_at进行比较,但实际上并不知道怎么做。

第二项
我想我应该以某种方式使用.strip来删除在使用可能意外放入的文本之前或之后的任何空格(我知道这些额外的空格默认在rails中使用,如果它们在那里可以使字段唯一。)

如果有人对如何正确完成这一点有任何暗示,我真的很感激。

2 个答案:

答案 0 :(得分:10)

validates_uniqueness_of通过检查记录是否已存在,并且给定范围内的给定字段的值相同。 :scope允许您定义唯一性的范围(显然);例如,如果我正在创建博客软件,并希望每个博客只允许使用一次帖子标题,我可以说validates_uniqueness_of :title, :scope => :blog_id - 没有范围,我只允许每个标题使用一次整个系统。 :scope不会让你做一个复杂的检查,就像你想要的那样。

您可能需要做的是创建自己的验证函数,以在给定的时间范围内检查相关字段的唯一性(代码在模型中):

validate :field_must_be_unique_within_six_months

def field_must_be_unique_within_six_months
  return if field.blank?
  num_duplicates = self.class.count(:conditions => ["field = ? AND created_at < ?", self.field, 6.months.ago])
  if num_duplicates > 0
    errors.add(:field, :taken)
  end
end

field_must_be_unique_within_six_months方法与validates_uniqueness_of的工作方式类似,因为如果已存在具有相同给定字段的记录,则会添加错误消息,但添加的条件是它还会检查日期。保存记录时,validate :field_must_be_unique_within_six_months会将方法添加到验证过程中。

要在不违反DRY的情况下同时验证多个字段,您可以使用validates_each执行以下操作:

validates_each :field1, :field2 do |record, attr, value|
  if record.class.exists?(["#{attr.to_s} = ? AND created_at < ?", value, 6.months.ago])
    errors.add(attr, :taken)
  end
end

在上面的区块中,record是要验证的记录,attr是属性(因此field1field2等)和value是该属性的值。

答案 1 :(得分:3)

你可以这样做:

def validate
    errors.add(:field, 'blah blah') if is_used_recently && !has_unique_field? 
end

def has_unique_field?
    Model.exists?(['field = ? and created_at > ?', self.field, 6.months.ago])
end 

def is_used_recently
    self.created_at < 6.months.ago || self.new? # i don't know if created_at would be set by this point
end

或者你可能想要创建一个新的验证处理程序,或者扩展现有的验证处理程序以传入:within选项,如果那是你经常要做的事情。

要摆脱前导和尾随空格,您想要的方法是“剥离”。您可以通过执行以下操作在所有字段上运行此操作:

before_validation :clean_up_whitespace

def clean_up_whitespace
    self.some_field.strip!    # this does the strip in place
end

我希望这会有所帮助,如果我犯了任何错误,请告诉我!