# 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 end1
2
3The key word
validatesprecedes the attributes to be validated (separated by commas), and is succeeded by thepresencevalidator, assigned the conditiontrue. Thepresencevalidator checks that the attribute is notnilor an emptystring.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 aboveirb> Person.create(name: "John Doe").valid? => true irb> Person.create(name: nil).valid? => false1
2
3
4[invalid?](https://api.rubyonrails.org/v7.0.4/classes/ActiveModel/Validations.html#method-i-invalid-3F)is the inverse ofvalid?. 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 } end1
2
3irb> 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 => 21
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
35Skipping 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_counterincrement!increment_counterinsertinsert!insert_allinsert_all!toggle!touchtouch_allupdate_allupdate_attributeupdate_columnupdate_columnsupdate_countersupsertupsert_all
Note that
savealso has the ability to skip validations if passedvalidate: falseas 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 end1
2
3length: 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 } end1
2
3
4
5
6uniqueness: 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 end1
2
3The 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
:scopeoption 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" } end1
2
3
4Should 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 } end1
2
3inclusion: 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" } end1
2
3
4Another 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]}1exclusion:
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." } end1
2
3
4format:
This method checks that the given attribute’s values match a given regular expression, which is specified using the
:withoption. Below is an example.class Product < ApplicationRecord validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/, message: "only allows letters" } end1
2
3
4numericality:
****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 } end1
2
3
4Besides
: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 thevalidatemethod which takes a record as an argument and performs the validation on it. The custom validator is called using thevalidates_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 end1
2
3
4
5
6
7
8
9
10
11
12The 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 avalidate_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 end1
2
3
4
5
6
7
8
9
10
11Custom 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 theerrorscollection 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 end1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16By 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 thevalidatemethod, with either::createor:updateclass Invoice < ApplicationRecord validate :active_customer, on: :create def active_customer errors.add(:customer_id, "is not active") unless customer.active? end end1
2
3
4
5
6
7Displaying 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
8Displaying message using flash
Now, what if the new article is saved successfully? How could we tell the user this?
Back in the
articles_controller.rbfile: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 end1
2
3
4
5
6
7
8
9Above we say if the article is saved successfully to the database, we use flash (opens new window) to pass a temporary message from the
createaction to theshowaction. Theshowaction will automatically pass the massage to its view. However, we can do something like this:In the
application.html.erbfile:<body> <% flash.each do |name, msg| %> <%= msg %> <% end %> <%= yield %> </body>1
2
3
4
5
6
← Model Relationships →