Posts tagged "validations"

One of the first things we learn in Rails which are greatly useful are ActiveRecord validations. However, since they are easy to add, it happens frequently that we are burdening our users with validations instead of making forms easier and clearer.

For instance, let’s suppose we are validating the Social Security Number (SSN) of an user on signup. A sample code would be:

1
2
3
4
5
6
7
class User < ActiveRecord::Base
  validates_presence_of :ssn
  validates_length_of :ssn, :is => 9
  validates_numericality_of :ssn
  validates_uniqueness_of :ssn
  validates_as_ssn :ssn # Checks if a reserved or special SSN was sent
end

With the configuration above, if the user forgets to fill in the SSN, leaving it blank, four error messages related to the SSN field will be shown:

  • SSN can’t be blank
  • SSN is the wrong length (should be 9 characters)
  • SSN is not a number
  • SSN is invalid

The question is: if the user just left the field blank, why we should show all those errors to him? Are they all relevant?

OMG! What have I done wrong to appear so many errors?

OMG! What have I done wrong to appear so many errors?

Luckily, the solution is quite simple: we can make use of the :allow_blank option, so other validations won’t be triggered if the field is blank:

1
2
3
4
5
6
7
class User < ActiveRecord::Base
  validates_presence_of :ssn
  validates_length_of :ssn, :is => 11, :allow_blank => true
  validates_numericality_of :ssn, :allow_blank => true
  validates_uniqueness_of :ssn, :allow_blank => true
  validates_as_ssn :ssn, :allow_blank => true
end

This is also a nice use case for the Object#with_options method added by Rails:

1
2
3
4
5
6
7
8
9
10
class User < ActiveRecord::Base
  validates_presence_of :ssn
 
  with_options :allow_blank => true do |v|
    v.validates_length_of :ssn, :is => 11
    v.validates_numericality_of :ssn
    v.validates_uniqueness_of :ssn
    v.validates_as_ssn :ssn
  end
end

SSN is just an example, but we are frequently burdening our users in username, e-mail, password and many other fields.

Do not validate presence of confirmation fields

Another interesting subject about validations are the confirmation fields. We have the following note in the documentation of validates_confirmation_of:

1
2
validates_confirmation_of :password
# NOTE: This check is performed only if password_confirmation is not nil

And this is a feature. This means that you don’t need to give the :password_confirmation key when creating objects in console or when writing tests:

1
2
3
it "should be valid with valid attributes" do
  User.new(:password => "123456").should be_valid
end

If the test fails, you are validating the presence of :password_confirmation, which is unnecessary. Since the :password_confirmation field will be available in the views, it will always be sent. So if the user leave it blank, it’s sent as blank value to the model and therefore will be checked. Just in the place it needs to be.