ActiveRecord Validations
Validating length of an attribute
Section titled “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 }endThe 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
Section titled “Validating presence of an attribute”This helper validates that the specified attributes are not empty.
class Person < ApplicationRecord validates :name, presence: trueend
Person.create(name: "John").valid? # => truePerson.create(name: nil).valid? # => falseYou 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: trueendNote:
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
Section titled “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
Section titled “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.
class StartsWithAValidator < ActiveModel::Validator def validate(record) unless record.name.starts_with? 'A' record.errors[:name] << 'Need a name starting with A please!' end endend
class Person < ApplicationRecord validates_with StartsWithAValidatorendActiveModel::EachValidator and validate
Section titled “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 endend
class Person < ApplicationRecord validates :email, presence: true, email: trueendMore information on the Rails guides.
Validates format of an attribute
Section titled “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/ }endYou 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
Section titled “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 }endBesides :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
Section titled “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 endendAll validations inside of the with_options block will have automatically passed the condition if: :is_admin?
Validates inclusion of an attribute
Section titled “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) }endTo 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) }endValidate uniqueness of an attribute
Section titled “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: trueendThere 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" }endThere 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 }endSkipping Validations
Section titled “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
Section titled “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 endendIf 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? }endFor negative conditional you can use unless:
class User < ApplicationRecord validates :first_name, presence: true, unless: Proc.new { |user| user.last_name.present? }endYou can also pass a string, which will be executed via instance_eval:
class User < ApplicationRecord validates :first_name, presence: true, if: 'last_name.blank?'endConfirmation of attribute
Section titled “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: trueendNote 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: trueendUsing :on option
Section titled “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: trueend