Rails Validations for Beginners

Published: 2014-09-26

Validations in Rails allow you to make sure that your users are entering data in a format that the applications expects and can use. Here is a pretty simple beginners guide on how to get started using validations in your application.
Using validations allows you to keep a watchful eye on data that is input into your application and to make sure that it is useable by the application.

Doing the data validations within Rails allows you to customize how errors are presented to the user. As the validations occur before a database INSERT or UPDATE command, this can protect your user from potentially bad mistakes.

Doing your validations at the model level ensures that no matter how the data is entered, the model will perform the final validations. Doing controller or view validations should not be relied upon as multiple controllers can access a single model.

The Setup

All the examples in the article will be built and tested using the following versions:
  • Rails: 4.1.5
  • Ruby 2.1.2
  • MiniTest 5.4.1

To help with the testing side of things, you can read my article on Rails Automated Testing Setup for Beginners to help you get setup with automated testing if you haven't already.

Standard Validations

Rails offers a lot of ways to validate your models, though here I will cover what I use on a regular basis and think of as 'Standard'.

Presence

My go to validation and probably the most basic validation, is to check that a field is actually there. Rails does this with the presence validation.

# single column check
class Post < ActiveRecord::Base
  validates :title, presence: true
end
# multiple column check
class Post < ActiveRecord::Base
  validates_presence_of :title, :body, :description
end
As you can see, a single line is all you need to make sure a field has some data in it.

Is it unique?

The next most common validation you are likely to use is the unique validation. This will check to make sure data is unique to that Model and you can even specify criteria by which to compare.

class Post < ActiveRecord::Base
  # regular uniqueness check
  validates :title, uniqueness: true
  # do a check that ignores case
  validates :title, uniqueness: { case_sensitive: false }
  # will only compare against other posts with the same post_type_id
  validates :title, uniqueness: { scope: :post_type_id }
end

Is it a Number?

You can check that a field is in a number format with the numericality validation.

The check by itself will validate the numbers 12 and 12.5 so to force it to check for integer only numbers you replace true with the hash { only_integer: true }

Finally, by doing this check it is also doing a presence check, so to ONLY check that the field is a number when there is data in it, add allow_blank: true to the end. This will only check the validation if the field is not blank and can be used on almost all validations.

class Post < ActiveRecord::Base
  # will validate both 12 and 12.5
  validates :review_score, numericality: true
  # will only validate 12
  validates :review_score, numericality: { only_integer: true }
  # will only validate 12 and only if the field is NOT blank. 
  validates :review_score, numericality: { only_integer: true }, allow_blank: true
end
The last line is the one I typically use most.

Displaying Error Messages

There are a lot of ways to build forms in Rails, though for our example, the standard Rails scaffold way of displaying error messages is as follows:

  # assuming @post is the form variable 
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@post.errors.count, "error") %> 
        prohibited this post from being saved:</h2>

      <ul>
      <% @post.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

What this does is to go through your @post object and check for errors and then display any error messages.

Rails has a default error message for each type of validation and these can be customized (see below).

Here are the standard error messages, the error is displayed as 'column_name' 'message'

  • presence - "can't be blank"
  • uniqueness - “has already been taken”
  • numericality - "is not a number"

Some examples:

validates :title, presence: true
# error message: Title can't be blank
validates :title, uniqueness: true
# error message: Title has already been taken
validates :review_score, numericality: true
# error message: Review score is not a number

Custom Error Messages

Built in errors not working for you? Easy, just add a custom message to your validations.

validates :title, presence: { message: 'should have some words in it' }
# error message: Title should have some words in it
validates :title, uniqueness: { message: 'was already used. Try something else' }
# error message: Title was already used. Try something else
validates :review_score, numericality: { message: 'should be a number' }
# error message: Review score should be a number

Testing your Validations

Rails provides a simple way to test your validations with the .valid? method.

By creating the object with or without the correct parameters you can easily check it is passing all validations with the .valid? check.

This .valid? works for all types of validations and is an easy way to test that your validations are working as designed.

Based on model

 validates_presence_of :title, :body

require 'test_helper'

class PostTest < ActiveSupport::TestCase
  test "validations are correct" do
    post = Post.new
    # post should not be valid as it is missing the title and body
    assert_not post.valid?
    post = Post.new(title: 'Post title')
    # post should not be valid as it is missing the body
    assert_not post.valid?
    post = Post.new(title: 'Post title', body: 'Post Body')
    assert post.valid?
  end
end

As you can see, its just a matter of providing missing, bad or good data to a model and then testing if it is valid. It is a good idea to make sure you are testing your validations with at least this basic test to make sure that they are working.

What next

We have only just scratched the surface of what you can do with validations. There is a lot you can do to help your users enter in valid data beyond what we have covered.

Read the Rails Guide for Active Record Validations to start diving deeper into validations.

Resources

RailsGuides for Validations - The Rails Guides page on Active Record Validations.

ActiveRecord Validations ClassMethods API Doc

Rails Automated Testing Setup for Beginners - My article on how to setup MiniTest for easy automated testing.


comments powered by Disqus