At Agira, Technology Simplified, Innovation Delivered, and Empowering Business is what we are passionate about. We always strive to build solutions that boost your productivity.

,

How To Validate Ruby Objects With Active Model Validations

  • By Venkata Krishna
  • November 23, 2018
  • 1452 Views

 

Why We Need Validations First?

With the help of validations you can ensure that only the valid data is saved into your database. For example, when your application demands unique email address for each users then we’re in a situation to collect only the valid data. Now you can achieve this with the help of Model level Validations in Rails. Rails provides several built-in helpers which will cover most of the validation part, Rails will also allows you to create your own custom validation methods.

Types of Validations?

There are many ways to validate your data before saving into your database and here i will list down the 4 main ways to validate the data in Rails.

  • Database Constraints – We can create validations at database level, but it is very difficult to manage validations at database level, because for every modification of validation you need to run the migration again. So maintenance will become more difficult.

 

  • Client side Validations – Client side validations are performed by browser, we will write these validations in JavaScript/Jquery, however we cannot use these validations alone. Because there might be a chance for Javascript is turned off in user browser, but these validation is very useful to give the immediate feedback to the user about what exactly went wrong. It is highly recommended to use both client and server side validations.

 

  • Controller-level Validations – We can add validations in your Rails Controller, but it is very difficult to test and maintain, Rails always will recommend us to keep the controller very light so that it will not add more code to your controller.

 

  • Model Level ValidationsRails always recommends to keep your validations at model level, this makes validations easy to test and maintain. In the coming section you could see how easy is that to add and test validations in Rails.

 

Validation Helpers in Rails?

 

  • Presence:

This Validator will not allow the record to save in DB unless specified attributes are present.
Example 1:
Model:

class User < ApplicationRecord
  validates :name, :email, :age, presence: true
end

Following example will throw error on empty name, email, age

user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: nil>
user.save
begin transaction
rollback transaction
user.errors.messages
=> {:name=>["can't be blank"], :email=>["can't be blank"], :age=>["can't be blank"]}

 

Related: Authenticating Rails Web Services With JWT

 

Absence:

This is the vice versa of the presence helper, this helper will always ensure that specified attribute must be empty.
Example:

class User < ApplicationRecord
 validates :email, :age, absence: true
end

Following example throws error on the presence of email.

user = User.new(name: 'Abcd', email: 'testuser@gmail.com', age: '22')
=> #<User id: nil, name: "Abcd", email: "testuser@gmail.com", created_at: nil, updated_at: nil, age: "22">
user.save
begin transaction
rollback transaction
user.errors.messages
=> {:email=>["must be blank"], :age=>["must be blank"]}

 

Uniqueness:

This helper always checks for the attribute uniqueness before record gets saved into the database.
Example:

class User < ApplicationRecord
 validates :email, uniqueness: true
end

In First example I created user with email testuser@gmail.com, in 2nd example when I try to create the user with same email, it throws error.

  1. 1) user = User.create(name: 'TestUser', email: 'testuser@gmail.com', age: '23')
    begin transaction
    (204.5ms)  commit transaction
    => #<User id: 5, name: "TestUser", email: "testuser@gmail.com", created_at: "2018-11-21 02:16:35", updated_at: "2018-11-21 02:16:35", age: "23">
    2) user = User.create(name: 'TestUser2', email: 'testuser@gmail.com', age: '24')
    begin transaction
    rollback transaction
    => #<User id: nil, name: "TestUser2", email: "testuser@gmail.com", created_at: nil, updated_at: nil, age: "24">
          user.errors.messages
         => {:email=>["has already been taken"]}

     

 

Numericality:

This helper will save the record into database only if the attribute value is numeric. You can also pass different constraints like :greater_than, :greater_than_or_equal_to, :equal_to, :less_than, :less_than_or_equal_to, :odd, :even, :other_than all the constraints are self explanatory.
Example:

class User < ApplicationRecord
 validates :age, numericality: true
end

In this example, I tried to create the user age with string which was expected to be number, so it throws error

 user = User.create(age: 'sdsdsd')
  (0.2ms)  begin transaction
  (0.2ms)  rollback transaction
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: "sdsdsd">
user.errors.messages
=> {:age=>["is not a number"]}

Following examples demonstrates how to use greater_than, less_than, other_than options with numericality helper.

class User < ApplicationRecord
 validates :age, numericality: { greater_than: 20, less_than: 90, other_than: 28 }
end
user= User.create(age: 12)
begin transaction
rollback transaction
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: "12">
user.errors.messages
=> {:age=>["must be greater than 20"]}
     user= User.create(age: 91)
begin transaction
rollback transaction
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: "91">
user.errors.messages
=> {:age=>["must be less than 90"]}
user= User.create(age: 28)
begin transaction
rollback transaction
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: "28">
user.errors.messages
=> {:age=>["must be other than 28"]}

Length:
This helper will validate the length of the attribute value and you can pass many constraints like minimum, maximum, in, is. “In” constraint for specifying length with in a range(which includes min and max values).”is” constraint for exact value length.
Example:
Following example demonstrates how to use length helper with different options like minimum, maximum, is, in.

class User < ApplicationRecord
 validates :name, length: { minimum: 2, maximum: 10 }
 validates :age, length: { is: 2 }
end
user=User.create(name: 'A', age: 222)
begin transaction
rollback transaction
user.errors.messages
=> {:name=>["is too short (minimum is 2 characters)"], :age=>["is the wrong length (should be 2 characters)"]}
user=User.create(name: 'Afdfdfdfdfdfdfdfdfdafe grst', age: 222)
begin transaction
rollback transaction
user.errors.messages
=> {:name=>["is too long (maximum is 10 characters)"], :age=>["is the wrong length (should be 2 characters)"]}
Following example demonstrates the length helper with in contraint.
class User < ApplicationRecord
 validates :name, length: { in: 2..10 }
end
user=User.create(name: 'A')
begin transaction
rollback transaction
user.errors.messages
=> {:name=>["is too short (minimum is 2 characters)"]}
user=User.create(name: 'Axfdfdsf sf sa fdasfdasfds fs dsfdsf')
begin transaction
rollback transaction
user.errors.messages
=> {:name=>["is too long (maximum is 10 characters)"]}

 

Best To Read: How To Build Rock Solid Ruby On Rails App With BDD

Inclusion:

This helper take a set of values and ensures that attribute value must match with any one of the value from the set of predefined values.
Example:

class User < ApplicationRecord
    validates :age, inclusion: { in: %w(10 20 30) }
end
user = User.create(age: 90)
begin transaction
rollback transaction
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: "90">
user.errors
=> #<ActiveModel::Errors:0x00000002f54d88 @base=#<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: "90">, @messages={:age=>["is not included in the list"]}, @details={:age=>[{:error=>:inclusion, :value=>"90"}]}>

 

Exclusion:

This is the total vice versa of inclusion helper, it will take a set of predefined values and it will ensure that attribute value must not match with any of the value in the list.
Example:

class User < ApplicationRecord
 validates :age, exclusion: { in: %w(10 20 30) }
end
user = User.create(age: 10)
begin transaction
rollback transaction
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: "10">
> user.errors
=> #<ActiveModel::Errors:0x00000001db7648 @base=#<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, age: "10">, @messages={:age=>["is reserved"]}, @details={:age=>[{:error=>:exclusion, :value=>"10"}]}>

 

Format:

This helper take input as a regular expression and ensures that attribute value must match with regular expression.
Example:

class User < ApplicationRecord
 validates :name, format: { with: /\A[a-zA-Z]+\z/, message: "only characters are allowed" }
end
user = User.create(name: '123')
begin transaction
rollback transaction
> user.errors
=> #<ActiveModel::Errors:0x00000004ccad90 @base=#<User id: nil, name: "123", email: nil, created_at: nil, updated_at: nil, age: nil>, @messages={:name=>["only characters are allowed"]}, @details={:name=>[{:error=>:invalid, :value=>"123"}]}>

 

Confirmation:

This helper is useful when you have text boxes in your form which expects the same values, for example email, email_confirmation, password, password_confirmation. This helper will creates a virtual attribute for you, you need to add _confirmation to the field.
Example:

class User < ApplicationRecord
 validates :email, confirmation: true
 validates :email_confirmation, presence: true
end
user = User.create(email: 'testuser@gmail.com')
begin transaction
rollback transaction
user.errors.full_messages
=> ["Email confirmation can't be blank"]

 

Acceptance:

This helper will always ensure that the checkbox in the form is checked when your form is submitted, one of the use case of this validation is, when the user is about to sign up then he/she must accept the term and conditions. Also, you don’t need to have any field in your database for this, rails will create a virtual attribute for you.
Example:

class User < ApplicationRecord
 validates :terms_of_service, acceptance: true
end

 

Allow_nil

There are some cases where you need to validate the attribute only if the attribute value is present, else we need to skip the validation. In that case allow_nil option skips the validation if the attribute value is nil and it will do the validation only when the attribute value present.
Example:
First example will save the record if age attribute value is nil, second example will return errors if age value is not in the specified list.

class User < ApplicationRecord
 validates :age, inclusion: { in: %w(10 20 30) }, allow_nil: true
end
user = User.create(name: 'Test', age: nil)
  begin transaction
 commit transaction
=> #<User id: 15, name: "Test", email: nil, created_at: "2018-11-23 01:49:10", updated_at: "2018-11-23 01:49:10", age: nil>
user = User.create(name: 'Test', age: 40)
begin transaction
rollback transaction
user.errors.full_messages
=> ["Age is not included in the list"]

Allow_blank

This option is almost similar to the allow_nil but only difference is “allow_nil” will accept the skip validation only when the value is nil where as allow_blank will skip the validation if the attribute value is nil, or empty string (“ ”)
Example:

class User < ApplicationRecord
 validates :age, inclusion: { in: %w(10 20 30) }, allow_blank: true
end
allow_nil throws error when age value is empty string
user = User.create(name: 'Test', age: "")
begin transaction
rollback transaction

Allow blank saves the record although age value is empty string,

user = User.create(name: 'Test', age: "")
begin transaction
commit transaction
=> #<User id: 16, name: "Test", email: nil, created_at: "2018-11-23 01:55:47", updated_at: "2018-11-23 01:55:47", age: "">

 

Message

By default each validation helper has the default error message set by the rails, this message option will allow you to customize the error messages for you.
Example:
The default validation error message of presence helper is “Name can’t be blank”(consider attribute name is “name”).

class User < ApplicationRecord
 validates :name, presence: { message: "is required" }
end
user = User.create(name: "")
  (0.2ms)  begin transaction
  (0.1ms)  rollback transaction
user.errors.full_messages
=> ["Name is required"]

In the same way, you can edit any validation helper error message.

On:

The default behavior of each validation helper is, they will run the validation before record gets stored into database i.e either while creating the record or while updating it. Also, this on option allow you to specify when the validation should happen.
Example:

class User < ApplicationRecord
 validates :age, presence: true, on: :create # skip validation on update
 validates :email, uniqueness: true, on: :update # skip validation on create
 validates :name, presence: { message: "is required" } # validates on create and update
end

Alright! Mostly we have seen covered all the major validations in Rails which can greatly help us in building user-centric forms. Also would appreciate your great suggestions to emphasize Rails validations. Concerned to build user centric site in Rails? Looking for the correct to take up? Get in touch with the highly skilled experts from Rails application development to guide you on building the user-friendly rails application.