# ActiveRecord Validations
# Validating length of an attribute
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
The possible length constraint options are:
:minimum
- The attribute cannot have less than the specified length.:maximum
- The attribute cannot have more than the specified length.:in
(or:within
) - The attribute length must be included in a given interval. The value for this option must be a range.:is
- The attribute length must be equal to the given value.
# Validating presence of an attribute
This helper validates that the specified attributes are not empty.
class Person < ApplicationRecord
validates :name, presence: true
end
Person.create(name: "John").valid? # => true
Person.create(name: nil).valid? # => false
You can use the absence
helper to validate that the specified attributes are absent. It uses the present?
method to check for nil or empty values.
class Person < ApplicationRecord
validates :name, :login, :email, absence: true
end
Note:
In case the attribute is a boolean
one, you cannot make use of the usual presence validation (the attribute would not be valid for a false
value). You can get this done by using an inclusion validation:
validates :attribute, inclusion: [true, false]
# Custom validations
You can add your own validations adding new classes inheriting from ActiveModel::Validator
or from ActiveModel::EachValidator
. Both methods are similar but they work in a slightly different ways:
# ActiveModel::Validator
and validates_with
Implement the validate
method which takes a record as an argument and performs the validation on it. Then use validates_with
with the class on the model.
# app/validators/starts_with_a_validator.rb
class StartsWithAValidator < ActiveModel::Validator
def validate(record)
unless record.name.starts_with? 'A'
record.errors[:name] << 'Need a name starting with A please!'
end
end
end
class Person < ApplicationRecord
validates_with StartsWithAValidator
end
# ActiveModel::EachValidator
and validate
If you prefer to use your new validator using the common validate
method on a single param, create a class inheriting from ActiveModel::EachValidator
and implement the validate_each
method which takes three arguments: record
, attribute
, and value
:
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || 'is not an email')
end
end
end
class Person < ApplicationRecord
validates :email, presence: true, email: true
end
More information on the Rails guides (opens new window).
# Validates format of an attribute
Validate that an attribute's value matches a regular expression using format
and the with
option.
class User < ApplicationRecord
validates :name, format: { with: /\A\w{6,10}\z/ }
end
You can also define a constant and set its value to a regular expression and pass it to the with:
option. This might be more convenient for really complex regular expressions
PHONE_REGEX = /\A\(\d{3}\)\d{3}-\d{4}\z/
validates :phone, format: { with: PHONE_REGEX }
The default error message is is invalid
. This can be changed with the :message
option.
validates :bio, format: { with: /\A\D+\z/, message: "Numbers are not allowed" }
The reverse also replies, and you can specify that a value should not match a regular expression with the without:
option
# Validating numericality of an attribute
This validation restricts the insertion of only numeric values.
class Player < ApplicationRecord
validates :points, numericality: true
validates :games_played, numericality: { only_integer: true }
end
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}".: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".
By default, numericality doesn't allow nil values. You can use allow_nil: true option to permit it.
# Grouping validation
Sometimes it is useful to have multiple validations use one condition. It can be easily achieved using with_options.
class User < ApplicationRecord
with_options if: :is_admin? do |admin|
admin.validates :password, length: { minimum: 10 }
admin.validates :email, presence: true
end
end
All validations inside of the with_options block will have automatically passed the condition if: :is_admin?
# Validates inclusion of an attribute
You can check if a value is included in an array using the inclusion:
helper. The :in
option and its alias, :within
show the set of acceptable values.
class Country < ApplicationRecord
validates :continent, inclusion: { in: %w(Africa Antartica Asia Australia
Europe North America South America) }
end
To check if a value is not included in an array, use the exclusion:
helper
class User < ApplicationRecord
validates :name, exclusion: { in: %w(admin administrator owner) }
end
# Validate uniqueness of an attribute
This helper validates that the attribute's value is unique right before the object gets saved.
class Account < ApplicationRecord
validates :email, uniqueness: true
end
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
There is also a :case_sensitive
option that you can use to define whether the uniqueness constraint will be case sensitive or not. This option defaults to true
.
class Person < ApplicationRecord
validates :name, uniqueness: { case_sensitive: false }
end
# Skipping Validations
Use following methods if you want to skip the validations. These methods will save the object to the database even if it is invalid.
- decrement!
- decrement_counter
- increment!
- increment_counter
- toggle!
- touch
- update_all
- update_attribute
- update_column
- update_columns
- update_counters
You can also skip validation while saving by passing validate
as an argument to save
User.save(validate: false)
# Conditional validation
Sometimes you may need to validate record only under certain conditions.
class User < ApplicationRecord
validates :name, presence: true, if: :admin?
def admin?
conditional here that returns boolean value
end
end
If you conditional is really small, you can use a Proc:
class User < ApplicationRecord
validates :first_name, presence: true, if: Proc.new { |user| user.last_name.blank? }
end
For negative conditional you can use unless
:
class User < ApplicationRecord
validates :first_name, presence: true, unless: Proc.new { |user| user.last_name.present? }
end
You can also pass a string, which will be executed via instance_eval
:
class User < ApplicationRecord
validates :first_name, presence: true, if: 'last_name.blank?'
end
# Confirmation of attribute
You should use this when you have two text fields that should receive exactly the same content. For example, you may want to confirm an email address or a password. This validation creates a virtual attribute whose name is the name of the field that has to be confirmed with _confirmation
appended.
class Person < ApplicationRecord
validates :email, confirmation: true
end
Note This check is performed only if email_confirmation
is not nil.
To require confirmation, make sure to add a presence check for the confirmation attribute.
class Person < ApplicationRecord
validates :email, confirmation: true
validates :email_confirmation, presence: true
end
# Using :on option
The :on
option lets you specify when the validation should happen.
The default behavior for all the built-in validation helpers is to be run on save (both when you're creating a new record and when you're updating it).
class Person < ApplicationRecord
# it will be possible to update email with a duplicated value
validates :email, uniqueness: true, on: :create
# it will be possible to create the record with a non-numerical age
validates :age, numericality: true, on: :update
# the default (validates on both create and update)
validates :name, presence: true
end