Email validation in Ruby On Rails 3 or Active model without regexp


In Rails 3.0, you can use custom validator in your active_record model.
So I wanted to manage email validations without regexp matching like others do.
I find a new way to make this work thanks to ruby mail gem, a dependency of Rails 3.0

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

Just put a file in app/validators/email_validator.rb

require 'mail'
class EmailValidator < ActiveModel::EachValidator
  def validate_each(record,attribute,value)
    begin
      m = Mail::Address.new(value)
      # We must check that value contains a domain and that value is an email address
      r = m.domain && m.address == value
      t = m.__send__(:tree)
      # We need to dig into treetop
      # A valid domain must have dot_atom_text elements size > 1
      # user@localhost is excluded
      # treetop must respond to domain
      # We exclude valid email values like <user@localhost.com>
      # Hence we use m.__send__(tree).domain
      r &&= (t.domain.dot_atom_text.elements.size > 1)
    rescue Exception => e   
      r = false
    end
    record.errors[attribute] << (options[:message] || "is invalid") unless r
  end
end

No regexp !! And beautiful !!

Here is the version without activerecord

require 'rubygems'
require 'active_model'
require 'active_support/all'
require 'active_model/validations'
require 'mail'
class EmailValidator < ActiveModel::EachValidator
  def validate_each(record,attribute,value)
    begin
      m = Mail::Address.new(value)
      # We must check that value contains a domain and that value is an email address
      r = m.domain && m.address == value
      t = m.__send__(:tree)
      # We need to dig into treetop
      # A valid domain must have dot_atom_text elements size > 1
      # user@localhost is excluded
      # treetop must respond to domain
      # We exclude valid email values like <user@localhost.com>
      # Hence we use m.__send__(tree).domain
      r &&= (t.domain.dot_atom_text.elements.size > 1)
    rescue Exception => e
      r = false
    end
    record.errors[attribute] << (options[:message] || "is invalid") unless r
  end
end
 
class Person
  include ActiveModel::Validations
  attr_accessor :name, :email
 
  validates :name, :presence => true, :length => { :maximum => 100 }
  validates :email, :presence => true, :email => true
end

, , , , , , , , , , , , , , , , , ,

  1. #1 by Sohan on July 21, 2010 - 16:31

    Your post has been linked at the Drink Rails blog as one of the top ruby on rails blogs of the day.

  2. #2 by Hallelujah on July 21, 2010 - 18:07

    Thanks a lot :)

(will not be published)