Rails 5 Validation Basics

Let's create a new user and check if it is valid.

 user = User.new
 => #<User id: nil, first_name: nil, middle_initial: nil, last_name: nil, created_at: nil, updated_at: nil, password: nil> 
 > user.valid?
 => false 

The user model has a validation for first_name.

class User < ApplicationRecord
  validates_presence_of :first_name

  def full_name
    [first_name, last_name].join(' ')
  end

  def full_name=(name)
    split = name.split(' ', 2)
    self.first_name = split.first
    self.last_name = split.last
  end
end

What are the errors? We can check for errors like this:

 user.errors
 => #<ActiveModel::Errors:0x007fe10 @base=#<User id: nil, first_name: nil, middle_initial: nil, last_name: nil, created_at: nil, updated_at: nil, password: nil>, @messages={:first_name=>["can't be blank"]}, @details={:first_name=>[{:error=>:blank}]}> 

We can retrieve the human readable error message like this:

 user.errors.full_messages
 => ["First name can't be blank"] 

Let's create a valid user object by providing the first_name.

 b = User.new(first_name: 'bugs')
 => #<User id: nil, first_name: "bugs", middle_initial: nil, last_name: nil, created_at: nil, updated_at: nil, password: nil> 

We can verify that it is valid.

 b.valid?
 => true 

From Rails Guides:

Active Record uses the new_record? instance method to determine whether an object is already in the database or not.

 user.new_record?
 => true 

How does Active Record know whether an object is saved in the database or not?

 user.id
 => nil

If the primary key is nil then it knows that the object has not been saved in the database yet. What happens when we use create method?

 daffy = User.create(first_name: 'daffy')
   (0.1ms)  begin transaction
  SQL (1.3ms)  INSERT INTO "users" ("first_name", "created_at", "updated_at") VALUES (?, ?, ?)  [["first_name", "daffy"], ["created_at", 2016-03-28 20:10:42 UTC], ["updated_at", 2016-03-28 20:10:42 UTC]]
   (0.5ms)  commit transaction

Active Record inserts the object into the database. We can check if the object that has been saved in the database is a new record or not.

 daffy.new_record?
 => false 

Active Record knows that it is not a new record because the primary key value has been populated.

 daffy.id
 => 1 

What happens when we change an attribute of an existing record and save it?

 daffy.first_name = 'duffy'
 => "duffy" 
 > daffy.save
   (0.1ms)  begin transaction
  SQL (0.9ms)  UPDATE "users" SET "first_name" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["first_name", "duffy"], ["updated_at", 2016-03-28 20:12:58 UTC], ["id", 1]]
   (0.5ms)  commit transaction
 => true 

In that cases, Active Record updates the existing record. You can bypass the validation by passing false for validate key.

 junk = User.new
 => #<User id: nil, first_name: nil, middle_initial: nil, last_name: nil, created_at: nil, updated_at: nil, password: nil> 
 > junk.save(validate: false)
   (0.1ms)  begin transaction
  SQL (0.8ms)  INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", 2016-03-28 20:20:18 UTC], ["updated_at", 2016-03-28 20:20:18 UTC]]
   (0.4ms)  commit transaction
 => true 

This is generally not a good idea. The user we just created is not a valid user.

 junk
 => #<User id: 2, first_name: nil, middle_initial: nil, last_name: nil, created_at: "2016-03-28 18:20:18", updated_at: "2016-03-28 20:20:18", password: nil> 
 > junk.valid?
 => false 

Active Record gives another method invalid?.

 junk.invalid?
 => true 

We can get list of all error messages as a hash like this:

 t = User.new
 => #<User id: nil, first_name: nil, middle_initial: nil, last_name: nil, created_at: nil, updated_at: nil, password: nil> 
 > t.errors.messages
 => {:first_name=>["can't be blank"]} 

We can get a specific error message for a field like this:

 t.errors[:first_name]
 => ["can't be blank"] 

We can check if a specific field has any error like this:

 t.errors[:first_name].any?
 => true 

We can also use the details method to get a list of errors for a given field.

 t.errors.details[:first_name]
 => [{:error=>:blank}] 

Summary

In this article, you learned the basics of Active Record validation in Rails 5.


Related Articles


Ace the Technical Interview

  • Easily find the gaps in your knowledge
  • Get customized lessons based on where you are
  • Take consistent action everyday
  • Builtin accountability to keep you on track
  • You will solve bigger problems over time
  • Get the job of your dreams

Take the 30 Day Coding Skills Challenge

Gain confidence to attend the interview

No spam ever. Unsubscribe anytime.