Validating that at least one attribute in a list is present: validates_presence_of_any
Make a lib/custom_validations.rb file, with these contents
module CustomValidations
def validates_presence_of_any(*attrs)
options = attrs.last.is_a?(Hash) ? attrs.pop.symbolize_keys : {}
attrs = attrs.flatten
send(validation_method(options[:on] || :save)) do |record|
return if options[:if] && !evaluate_condition(options[:if], record)
attr_list = attrs.map{|a| a.to_s.humanize}.to_sentence(:connector => "or", :skip_last_comma => true)
record.errors.add :base, "Either #{attr_list} needed." if attrs.all?{ |attr| record.send(attr).blank?}
end
end
end
and then “extend CustomValidation” in your model.
Then you can
validates_presence_of_any :first_attr, :second_attr, :third_attr
Thanks to bitsweat on #caboose for help with a succinct name that follows the convention.
Doing a rails custom validator with-out using validates_each
I wanted to do a custom validator (forthcoming post) that validates that at least one out of a list of attributes is present (validates_presence_of_any). Unfortunately, all the examples I could find use validates_each (see here for a decent example on the topic in general), and since mine depends on the list as a whole, that doesn’t quite fit. So I just stole some of the guts of validates each, to get the magic reference to the record object. As a bonus, then my validation conforms to other validation conventions, like accepting :if => in an options hash.
def self.validates_your_funky_non_validates_each_using_way(*attrs)
options = attrs.last.is_a?(Hash) ? attrs.pop.symbolize_keys : {}
attrs = attrs.flatten
# Declare the validation.
send(validation_method(options[:on] || :save)) do |record|
return if options[:if] && !evaluate_condition(options[:if], record)
#put real code using attrs and record here
record.errors.add :base, "monkey", if record.primate?
end
end

Articles via rss or email