validates_uniqueness_of
works by checking if a record already exists with the same value of the given field within the given scope. :scope
lets you define the scope (obviously) of the uniqueness; for instance, if I was creating blog software and wanted to only allow a post title to be used once per blog, I could say validates_uniqueness_of :title, :scope => :blog_id
-- without the scope, I'd only be allowing each title to be used once across the entire system. :scope
won't let you do a complex check, like that which you desire.
What you're probably need to do is create your own validation function to check the uniqueness of the field in question within the given timeframe (code goes within the model):
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
The field_must_be_unique_within_six_months
method will work similarly to validates_uniqueness_of
, in that it will add an error message if there is already a record with the same given field, but with the added condition that it will also check the date. The validate :field_must_be_unique_within_six_months
will add the method to the validation process when a record is saved.
To validate multiple fields at the same time without violating DRY, you could use validates_each to do something like the following:
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
In the above block, record
is the record being validated, attr
is the attribute (so field1
, field2
, etc.) and value
is the value of that attribute.