Gettings Started with Custom Rails3 Validators

Posted Posted by Samuel Mullen in Blog     Comments 2 comments
Nov
8

Nobody likes bad data. There is little worse than having malformed or incorrect values in your data stream. Thankfully, Ruby on Rails has a tool for mitigating the insertion of bad data: validations. Validations are ruby methods which are run prior to data being saved to your database. Prior to Rails3, they took the form of validates_presence_of, validates_uniqueness_of, validates_awesomeness_of, and so on.

Now, in Rails3, validations not only support these legacy methods, but validations also implement Jamie Hill‘s new “Sexy Validations“. With this new implementation, the focus is transfered from the validation itself to the attribute to be validated:

Prior to Rails3:

class User < ActiveRecord::Base
  validates_presence_of :username
  validates_uniqueness_of :username
  validates_length_of :username, :minimum => 6, :maximum => 32
end

Rails3:

class User < ActiveRecord::Base
  validates :user, :presence => true, :uniqueness => true, :length => 6..32
end

As you can see, in the first example, the focus is on the validation itself, in the second example the focus is on the field to be validated.

But what if we need a validator which doesn’t currently exist in Rails or is unique to our project? Answer: Custom Validators.

The first thing you will need to do is create a directory under your project’s “lib” directory. It’s not necessary to do this, but it helps with organization. From your projects root directory, execute the following command:

mkdir lib/validators

In your “config/application.rb” file, you will need to add the following line to let the Rails engine know where all of your custom validations are:

config.autoload_paths += Dir["#{config.root}/lib/**/"]

For the purpose of example, we’re going to implement a validator to check the validity of an email address using a regular expression created by James Watts and Francisco Jose Martin Moreno (http://fightingforalostcause.net/misc/2006/compare-email-regex.php).

Create the file “email_pattern_validator.rb” under your lib/validators directory and add the following code to it:

class EmailPatternValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value.nil? || !value.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i)
      record.errors[attribute] << "Not a valid email address"
    end
  end
end

Don’t get caught up in the regular expression: You will go blind by the sheer awesomeness of it. Instead, look at the classname, the method, and the “record.errors” line.

First, the class name must be the camelcase version of the file name and both names must end in validator. These conventions let the Rails engine know that this is a validator.

Second, the method “validate_each” receives three values: the record to be saved, the attribute to be validated, and the value of the field to be validated. In our example, and likely in your own projects, this is what we validate against.

Lastly, The “record.errors” records errors for the attribute (database column) upon which errors are found.

Now, in our models we can use the follow bit of code to check the validity of email address:

validates :email, :email_pattern => true

Please note that the validator “email_pattern” matches the file name and class name we created sans the “_validator”. That’s part of that whole “Convention over Configuration” thing I keep hearing about. If it’s a valid email address, we’re golden; if not, we’ll have the “Not a valid email address” error applied to our model instance.

This is just scratching the surface of what’s possible with Rails3 validators. For more information, I would encourage you to check out the resources below. The last one is a reference to the email regular expression.

References:
* http://thelucid.com/2010/01/08/sexy-validation-in-edge-rails-rails-3/
* http://omgbloglol.com/post/392895742/improved-validations-in-rails-3
* http://lindsaar.net/2010/1/31/validates_rails_3_awesome_is_true
* http://fightingforalostcause.net/misc/2006/compare-email-regex.php

2 Comments to “Gettings Started with Custom Rails3 Validators”

  • Thanks, this was really clear and helpful!

  • Fantastic, thank you! – Added a custom :ip validator :P

Post comment

about databasically

We live and work in Kansas City, USA.

We're passionate about helping small businesses succeed and want to help you use technology to get more done.

From server, desktop, network management to programming custom web applications in Ruby on Rails, we're here to lend a hand.

Contact us if you have any questions!