Gettings Started with Custom Rails3 Validators

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

Established 2005 · Databasically © 2016