Tuesday, June 10, 2008

invalidates_format_of

Have you ever found yourself wanting an invalidates_format_of or validates_format_not method. For example, maybe you want to make sure a name field doesn't have 2 or more consecutive spaces, there's not regular expression that I can come up with that will positively match a string that does NOT have 2 consecutive spaces.

Even if there is a regular expression that does that, let's assume for the sake of this article that you have a situation where you can't easily come up with a regular expression that describes what you want but you CAN come up with a regular expression that describes what you don't want. In that case, you'd really like something like:


# too bad this doesn't work...
invalidates_format_of :name, :with => /\s{2,}/, :message => "can't have consecutive spaces"

Unfortunately, invalidates_format_of doesn't exist but validates_each comes to the rescue. The validates_each method allows you to build just about any type of validator you could ever want. To build the equivalent of invalidates_format_of, all you have to do is this:

# invalidates_format_of
validates_each :name, :on => :create do |model, attr, value|
if value =~ /\s{2,}/
model.errors.add(attr, "can't have consecutive spaces")
end
end

This technique could certainly be used to create your own validates_absence_of, validates_non_uniquess_of or any other method that doesn't quiet meet your requirements. For example, if you want a method that validates uniqueness of a name but only if it's not nil (i.e. nil is allowed but name must be unique if it's not nil), then try this:

# validates_nil_or_uniqueness_of
validates_each :name, :on => :create do |model, attr, value|
if model.name != nil && model.class.find_by_name(value)
model.errors.add(attr, "is already taken")
end
end

Piece of cake... I hope that helps someone out there on the interwebs.

0 comments: