Custom validations in Rails 3

Today, I am writing the blog post with my late apologization. Sorry to all of my readers and followers for not writing any good posts on the last couple of days. I am passing very busy time for the office project as well as my Grad school. By the way, I started my new career at IOU Finance Inc. as Software Engineer. The company has a nice, secure and scalable financial platform based on Ruby on Rails (Rails framework version 3) where right now I am working on. Whatever, last of couple of days I wrote several rails 3 validator in order to clean up some historical data. Now, I will talk about how easily you can write your own customized validator to validate your model data.

In Rails 3, ActiveRecord comes with some modules likes Serialization, Errors, Dirty, Callbacks, and validations. There are basically two types of validator modules are included in ActiveRecord. One is ActiveModel::Validations which takes care validation in the model layer, and another one is ActiveRecord::Validations works as database layer validations likes uniqueness, associate. This is all about the basic idea. For now, writing a custom validation you will have to extend it from ActiveModel::Validator or from ActiveModel::EachValidator. Here again, ActiveModel::Validator works with one record and ActiveModel::EachValidator works with attributes. I will show the example each of them.

Let’s start with the first one, which extends from ActiveModel::Validator and takes a record to validate. Create a file with your validator name, for example: IsWordExistsValidator under the lib directory of your application. One thing is that needs to be mentioned here you will have to implement a validate method.

In directory, it will be look like as follows
/lib/is_word_exists_validator.rb

# lib/is_word_exists_validator.rb
class IsWordExistsValidator < ActiveModel::Validator
  WORDS = %w(john robert)
 
  def validate(record)
    unless WORDS.include?record.name 
      record.errors[:name] << "It's not a valid string."
    end
  end  
end

Now, in your model class just add the following lines..

class User < ActiveRecord::Base
  validates :name, is_word_exists: true
end

If your model doesn’t extend from ActiveRecord, then you will have to include the validator manually.

class User 
  include ActiveModel::Validations
  validates_with IsWordExistsValidator
end

Now, I will show the vlaidator with ActiveModel::EachValidator which takes the attributes: record, attribute, value. Again your have to create file as same as validator class name under the lib directory. In this case, keep it in your mind that you must implement the validate_each method.

# lib/is_word_exists_validator.rb
class IsWordExistsValidator < ActiveModel::EachValidator
  WORDS = %w(john robert)
 
  # it accepts custom error message
  def validate_each(record, attribute, value)
    record.errors[attribute] << (options[:message] || "It's not a valid string.") unless WORDS.include?(value)
  end  
end

Add the validator in your model…

class User < ActiveRecord::Base
  validates :name, :presence => true, :is_word_exists => true
end

You pass something :message => “some error message”, then validator will print this message instead the default one.

You can also use this validator in following way..

user = User.new(name: 'john')
user.valid?     #=>  true

Done. You can write your own Rails validator right away.

 

Eftakhairul Islam

Hi, I'm Eftakhairul Islam, a passionate Software Engineer, Hacker and Open Source Enthusiast. I enjoy writing about technical things, work in a couple of startup as a technical advisor and in my spare time, I contribute a lot of open source projects.

 

Leave a Reply

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Read previous post:
load, require, include and extend in Ruby with module and mix-ins concept

Nowadays, a lot of programmers are switching to Ruby language for its awesomeness. Most of them are having the problem...

Close