Validating Mutually-Exclusive Attributes 5
Let’s say you have a model that holds a location, with a “state” and a “country”. Suppose that you want the user to enter either a state or a country, but not both.
Your first instinct might be to do something like this:
validates_presence_of :state, :if => lambda {|row| row.country.blank?}
validates_presence_of :country, :if => lambda {|row| row.state.blank?}That’s not quite right however. You won’t get an error if both a state and a country are entered. Furthermore, if both attributes are entered, which one should be considered “wrong”?
Here’s where the generic validate method can help. Rather than validating a specific attribute, validate works on the whole row. If you need to add error messages you use the ActiveRecord::Errors#add() and #add_to_base() methods.
The validation for our state/country example looks like this:
validate do |row|
if row.state.blank? ^ row.country.blank?
row.errors.add_to_base 'Either a state or a country is required (but not both)'
end
endNote how validate takes a block. The row being saved is passed to the block. The caret (^) is Ruby’s “exclusive-or” operator. It returns true only if exactly one of its operands is true, which fits our requirements perfectly.
The add_to_base method adds an error message to the list of errors for the row, but the message is not specific to any single attribute. In this case, the error relates to two attributes, so I chose to use add_to_base.
Hi Bob – just found your blog. you should post more often. there are a number of places i could have used this validation block feature. was this new in rails 1.2.3?
chad: no, this validate method has been around since the early days of Rails.
Could you explain how the giving a block is more useful then to validate without? Where is it different to:
def validate if name.blank? && email.blank? errors.add_to_base(“You must specify a name or an email address”) end end
nioloash: I think the main advantage of using the validate class method with a block is that you can specify it multiple times, which allows you to logically separate your validations.
Other than that there is no real advantage.
Try rssnewsdigest.com, a new comprehensive news aggregator. With rssnewsdigest, you don ’t really have to go anywhere else. http://rssnewsdigest.com