# Validation

Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not already in the database, follows a specific format, and many more.

  • Writing Validation Logic

    class Person < ApplicationRecord
      validates :name, presence: true
    end
    
    1
    2
    3

    The key word validatesprecedes the attributes to be validated (separated by commas), and is succeeded by the presencevalidator, assigned the condition true. The presence validator checks that the attribute is notnil or an empty string.

    We will discuss about other validator latter.

    Before saving an Active Record object, Rails runs your validations. If these validations produce any errors, Rails does not save the object.

    You can also run these validations on your own. [valid?](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/Validations.html#method-i-valid-3F) triggers your validations and returns true if no errors were found in the object, and false otherwise. As you saw above

    irb> Person.create(name: "John Doe").valid?
    => true
    irb> Person.create(name: nil).valid?
    => false
    
    1
    2
    3
    4

    [invalid?](https://api.rubyonrails.org/v7.0.4/classes/ActiveModel/Validations.html#method-i-invalid-3F)is the inverse of valid?. It triggers your validations, returning true if any errors were found in the object, and false otherwise.

  • Working With Error Messages

    The [valid?](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/Validations.html#method-i-valid-3F) and [invalid?](https://api.rubyonrails.org/v7.0.4/classes/ActiveModel/Validations.html#method-i-invalid-3F) methods only provide a summary status on validity. However you can dig deeper into each individual error by using various methods from the  [errors](https://api.rubyonrails.org/v7.0.4/classes/ActiveModel/Validations.html#method-i-errors)  collection.

    class Person < ApplicationRecord
      validates :name, presence: true, length: { minimum: 3 }
    end
    
    1
    2
    3
     
    
    irb> person = Person.new(name: "JD")
    irb> person.valid?
    => false
    irb> person.errors[:name]
    => ["is too short (minimum is 3 characters)"]
    
    #where 
    
    irb> person.errors.where(:name)
    => [ ... ] # all errors for :name attribute
    
    irb> person.errors.where(:name, :too_short)
    => [ ... ] # :too_short errors for :name attribute
    
    #error object
    
    irb> error = person.errors.where(:name).last
    
    irb> error.attribute
    => :name
    irb> error.type
    => :too_short
    irb> error.options[:count]
    => 3
    
    irb> error.message
    => "is too short (minimum is 3 characters)"
    irb> error.full_message
    => "Name is too short (minimum is 3 characters)"
    
    #error size
    irb> person.errors.size
    => 2
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
  • Skipping Validations

    The following methods skip validations, and will save the object to the database regardless of its validity. They should be used with caution.

    • decrement!
    • decrement_counter
    • increment!
    • increment_counter
    • insert
    • insert!
    • insert_all
    • insert_all!
    • toggle!
    • touch
    • touch_all
    • update_all
    • update_attribute
    • update_column
    • update_columns
    • update_counters
    • upsert
    • upsert_all

    Note that save also has the ability to skip validations if passed validate: false as an argument. This technique should be used with caution.

    • save(validate: false)
  • Available Validation Rule

    presence: This method simply checks that the specified attribute(s) are not empty. In the below example the validation is ensuring that the name, login and email attributes are not empty.

    class Person < ApplicationRecord
      validates :name, :login, :email, presence: true
    end
    
    1
    2
    3

    length: This method checks the length of the given attribute’s value. It provides several different constraints: minimum, maximum, is and in. See below for an example.

    class Person < ApplicationRecord
      validates :name, length: { minimum: 2 }
      validates :bio, length: { maximum: 500 }
      validates :password, length: { in: 6..20 }
      validates :registration_number, length: { is: 6 }
    end
    
    1
    2
    3
    4
    5
    6

    uniqueness: This method check that a given attribute’s value is unique. In the below example the validation will check that value entered for the email attribute is unique. This method also allows you to add scope to specify one or more attributes to use as a limit for the uniqueness.

    class Account < ApplicationRecord
      validates :email, uniqueness: true
    end
    
    1
    2
    3

    The validation happens by performing an SQL query into the model's table, searching for an existing record with the same value in that attribute.

    There is a :scope option that you can use to specify one or more attributes that are used to limit the uniqueness check:

    class Holiday < ApplicationRecord
      validates :name, uniqueness: { scope: :year,
        message: "should happen once per year" }
    end
    
    1
    2
    3
    4

    Should you wish to create a database constraint to prevent possible violations of a uniqueness validation using the :scopeoption, you must create a unique index on both columns in your database.

    There is also a :case_sensitiveoption that you can use to define whether the uniqueness constraint will be case sensitive, case insensitive, or respects default database collation. This option defaults to respects default database collation.

    class Person < ApplicationRecord
      validates :name, uniqueness: { case_sensitive: false }
    end
    
    1
    2
    3

    inclusion: This method checks that the given attribute’s values are included in a given set. Below, the validation method is checking that the attribute size includes either small, medium or large.

    class Coffee < ApplicationRecord
      validates :size, inclusion: { in: %w(small medium large),
        message: "%{value} is not a valid size" }
    end
    
    1
    2
    3
    4

    Another useful way to utilize the inclusion validation method is to check for true/false values. See below for an example:

    validates :boolen_field_name,  inclusion: {in: [true, false]}
    
    1

    exclusion:

    This method checks that the given attribute’s values are NOT included in a given set. In the example below, the validation is checking that in the subdomain attribute, “www”, “us”, “ca” and “jp” are not included. If a user tried to set the subdomain’s attribute as any of those strings, they would receive an error.

    class Account < ApplicationRecord
      validates :subdomain, exclusion: { in: %w(www us ca jp),
        message: "%{value} is reserved." }
    end
    
    1
    2
    3
    4

    format:

    This method checks that the given attribute’s values match a given regular expression, which is specified using the :with option. Below is an example.

    class Product < ApplicationRecord
      validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/,
        message: "only allows letters" }
    end
    
    1
    2
    3
    4

    numericality:

    ****This method checks that the given attribute has only numeric values. If you’d like to further specify only integral numbers, you would then follow numericality with :only_integer: true. In the below example the validation is checking that the points attribute is a number (integer or float). The next validation is checking that the games_played attribute is specifically an integer number.

    class Player < ApplicationRecord
      validates :points, numericality: true
      validates :games_played, numericality: { only_integer: true }
    end
    
    1
    2
    3
    4

    Besides :only_integer, this helper also accepts the following options to add constraints to acceptable values:

    • :greater_than - Specifies the value must be greater than the supplied value. The default error message for this option is "must be greater than %{count}".
    • :greater_than_or_equal_to - Specifies the value must be greater than or equal to the supplied value. The default error message for this option is "must be greater than or equal to %{count}".
    • :equal_to - Specifies the value must be equal to the supplied value. The default error message for this option is "must be equal to %{count}".
    • :less_than - Specifies the value must be less than the supplied value. The default error message for this option is "must be less than %{count}".
    • :less_than_or_equal_to - Specifies the value must be less than or equal to the supplied value. The default error message for this option is "must be less than or equal to %{count}".
    • :other_than - Specifies the value must be other than the supplied value. The default error message for this option is "must be other than %{count}".
    • :in - Specifies the value must be in the supplied range. The default error message for this option is "must be in %{count}".
    • :odd - Specifies the value must be an odd number if set to true. The default error message for this option is "must be odd".
    • :even - Specifies the value must be an even number if set to true. The default error message for this option is "must be even".

    You can view all the validator options below

    Active Record Validations - Ruby on Rails Guides (opens new window)

  • Custom Validation Rule

    Custom Validators

    Custom validators are classes that inherit from [ActiveModel::Validator](https://api.rubyonrails.org/v7.0.4/classes/ActiveModel/Validator.html). These classes must implement the validatemethod which takes a record as an argument and performs the validation on it. The custom validator is called using the validates_withmethod.

    class MyValidator < ActiveModel::Validator
      def validate(record)
        unless record.name.start_with? 'X'
          record.errors.add :name, "Need a name starting with X please!"
        end
      end
    end
    
    class Person
      include ActiveModel::Validations
      validates_with MyValidator
    end
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    The easiest way to add custom validators for validating individual attributes is with the convenient [ActiveModel::EachValidator](https://api.rubyonrails.org/v7.0.4/classes/ActiveModel/EachValidator.html). In this case, the custom validator class must implement a validate_eachmethod which takes three arguments: record, attribute, and value. These correspond to the instance, the attribute to be validated, and the value of the attribute in the passed instance.

    class EmailValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
          record.errors.add attribute, (options[:message] || "is not an email")
        end
      end
    end
    
    class Person < ApplicationRecord
      validates :email, presence: true, email: true
    end
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    Custom Methods

    You can also create methods that verify the state of your models and add errors to the errorscollection when they are invalid. You must then register these methods by using the [validate](https://api.rubyonrails.org/v7.0.4/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate) class method, passing in the symbols for the validation methods' names.

    You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered.

    The valid? method will verify that the errors collection is empty, so your custom validation methods should add errors to it when you wish validation to fail:

    class Invoice < ApplicationRecord
      validate :expiration_date_cannot_be_in_the_past,
        :discount_cannot_be_greater_than_total_value
    
      def expiration_date_cannot_be_in_the_past
        if expiration_date.present? && expiration_date < Date.today
          errors.add(:expiration_date, "can't be in the past")
        end
      end
    
      def discount_cannot_be_greater_than_total_value
        if discount > total_value
          errors.add(:discount, "can't be greater than total value")
        end
      end
    end
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    By default, such validations will run every time you call valid?or save the object. But it is also possible to control when to run these custom validations by giving an :onoption to the validatemethod, with either: :createor :update

    class Invoice < ApplicationRecord
      validate :active_customer, on: :create
    
      def active_customer
        errors.add(:customer_id, "is not active") unless customer.active?
      end
    end
    
    1
    2
    3
    4
    5
    6
    7
  • Displaying Errors in frontend

    <% if @article.errors.any? %>
      <h3>The following errors prevented the article from being saved:</h3>
      <ul>
        <% @article.errors.full_messages.each do |msg| %>
         <li><%= msg %></li> 
        <% end %>
      </ul>
    <% end %>
    
    1
    2
    3
    4
    5
    6
    7
    8

    Displaying message using flash

    Now, what if the new article is saved successfully? How could we tell the user this?

    Back in the articles_controller.rb file:

    def create
        @article = Article.new(params.require(:article).permit(:title, :description))
        if @article.save
          flash[:notice] = "This article was saved successfully"
          redirect_to @article
        else 
          render 'new'
        end
    end
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    Above we say if the article is saved successfully to the database, we use flash (opens new window) to pass a temporary message from the create action to the show action. The show action will automatically pass the massage to its view. However, we can do something like this:

    In the application.html.erb file:

    <body>
       <% flash.each do |name, msg| %>
         <%= msg %>
       <% end %>
       <%= yield %>
    </body>
    
    1
    2
    3
    4
    5
    6