Validating email addresses in Rails

Thoughts from the team
By    | September 19, 2011 | Development, Tips & Tricks,

In response to Adam’s last post on how to validate email addresses in ASP.NET MVC I thought I’d quickly explain how you might do it in Ruby on Rails, and then explain why you should never do it like this.

How not to do it

Like this…

class User < ActiveRecord::Base
  validates :email,
            :format => {
              :with    => /^([^\s]+)((?:[-a-z0-9]\.)[a-z]{2,})$/i,
              :message => "Only letters allowed" }
end

Yeah, that’s it.  One line of code (if you strip out the line-breaks).  God I love Rails.

That will check the format every time the object gets saved.  If you want to be more specific about when to check you can add

  :on => :create

to only check when a new object is created, or

  :on => :update

to only check when an existing object is updated.

Of course format validation is very useful, but you should never roll your own for checking a standard when one already exists, especially for something as old as email.

Why?

  • The format of a valid email address as defined by RFC5322 (You have heard of RFC5322 right?) is a lot more complex than most people realise and way more complex than the simple regex above.
  • Most hand-rolled regexes are often too strict (I will hunt you down and beat you to death with a stone engraving of RFC5322 if you don’t let me use ‘+’ addressing). Or they are too loose, in which case you’ll probably end up trying to send emails to invalid addresses, and why would you want to do that?
  • If someone else has already written code to do something, use it, don’t roll your own, that’s just silly, you’ll probably just get it wrong at least once.

Sadly, far too many web-developers like to roll their own, which gives people like me the rage when they can’t use + addressing because it’s too strict, or it didn’t catch my obvious typo because it was too loose.

The best example I’ve heard of is a site that lets you sign up using a + address (e.g. myname+yoursitename@example.com) but won’t then let you login using the same address…

How You Should Really Do it

Add the following to your Gemfile (other email validation gems are available)

  gem 'validates_email_format_of'

Run Bundler to install it, obviously.

Then it’s just…

class Person < ActiveRecord::Base
   validates :email, :email_format => {:message => 'is not looking good'}
end

Hey-presto, all email addresses for that model will be valid (although no guarantees that they will be right).

Your code is simpler, and you can be pretty sure that the library is correct because it’s been used by a heck of a lot more people than your hand-rolled regex.

More like this