views:

31

answers:

2

I have a basic Rails model with two properties, name and code. I have validates_uniqueness_of for the code property. However, I'd like to customize the :message to show the name of the duplicate. Is there any way to access this duplicate item?

For example, say I first enter a record called Expired with code EXP. Then I enter Experience with code EXP. I would like the :message to say something like "Code already taken by Expired".

> m1 = Model.new(:name => 'Expired', :code => 'EXP')
> m2 = Model.new(:name => 'Experience', :code => 'EXP')
> m1.save!
> m2.save!

validates_uniqueness_of :code,
  :message => "Code already taken by #{duplicate.name}"

Is there any built-in Rails construct that holds the duplicate object so that I can access it like I do in the :message? Or is there any other way I can run code to determine the duplicate when this validation gets triggered?

+1  A: 

I believe you'd have to write a custom validation method. Something like:

def validate
   model = Model.first(:conditions => {:code => self.code})
   unless model.blank?
     errors.add_to_base "Code already taken by #{model.name}"
   end
end
j.
Great! Works like a charm! Don't know why I've never known about this over why I couldn't find anything about it. Thanks a lot!
istrasci
You're welcome :]
j.
Thought I'd add that we need to add logic to make sure _self.id_ is not the same as _model.id_. Otherwise we'll never be able to update an existing item (unless that's the behaviour you want).
istrasci
A: 

As per @j but as a validation callback and target the message specifically to the failing attribute

validate do |model|
   duplicate = Model.first(:conditions => {:code => model.code})
   if duplicate
     model.errors.add :code, "already taken"
   end
end
bjg