method

validates

validates(*attributes)
public

This method is a shortcut to all default validators and any custom validator classes ending in ‘Validator’. Note that Rails default validators can be overridden inside specific classes by creating custom validator classes in their place such as PresenceValidator.

Examples of using the default rails validators:

validates :terms, acceptance: true
validates :password, confirmation: true
validates :username, exclusion: { in: %w(admin superuser) }
validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, on: :create }
validates :age, inclusion: { in: 0..9 }
validates :first_name, length: { maximum: 30 }
validates :age, numericality: true
validates :username, presence: true
validates :username, uniqueness: true

The power of the validates method comes when using custom validators and default validators in one call for a given attribute.

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.errors.add attribute, (options[:message] || "is not an email") unless
      value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
  end
end

class Person
  include ActiveModel::Validations
  attr_accessor :name, :email

  validates :name, presence: true, uniqueness: true, length: { maximum: 100 }
  validates :email, presence: true, email: true
end

Validator classes may also exist within the class being validated allowing custom modules of validators to be included as needed.

class Film
  include ActiveModel::Validations

  class TitleValidator < ActiveModel::EachValidator
    def validate_each(record, attribute, value)
      record.errors.add attribute, "must start with 'the'" unless value =~ /\Athe/i
    end
  end

  validates :name, title: true
end

Additionally validator classes may be in another namespace and still used within any class.

validates :name, :'film/title' => true

The validators hash can also handle regular expressions, ranges, arrays and strings in shortcut form.

validates :email, format: /@/
validates :gender, inclusion: %w(male female)
validates :password, length: 6..20

When using shortcut form, ranges and arrays are passed to your validator’s initializer as options[:in] while other types including regular expressions and strings are passed as options[:with].

There is also a list of options that could be used along with validators:

  • :on - Specifies when this validation is active. Runs in all validation contexts by default (nil), other options are :create and :update.

  • :if - Specifies a method, proc or string to call to determine if the validation should occur (e.g. if: :allow_validation, or if: Proc.new { |user| user.signup_step > 2 }). The method, proc or string should return or evaluate to a true or false value.

  • :unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. unless: :skip_validation, or unless: Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

  • :strict - if the :strict option is set to true will raise ActiveModel::StrictValidationFailed instead of adding the error. :strict option can also be set to any other exception.

Example:

validates :password, presence: true, confirmation: true, if: :password_required?
validates :token, uniqueness: true, strict: TokenGenerationException

Finally, the options :if, :unless, :on, :allow_blank, :allow_nil, :strict and :message can be given to one specific validator, as a hash:

validates :password, presence: { if: :password_required?, message: 'is forgotten.' }, confirmation: true

9Notes

multiple attributes with the same validations

bradcantin · Jun 18, 20108 thanks

You can list multiple attributes if they share the same validations

validates :title, :body, :presence => true

sending the attributes as an array will return an error

validates [:title, :body], :presence => true
#=> ArgumentError: Attribute names must be symbols

case-insensitive uniqueness

zubin · Feb 20, 20118 thanks

For case-insensitive uniqueness:

validate :username, :uniqueness => {:case_sensitive => false}

uniqueness

bradcantin · Jul 14, 20107 thanks

You can scope uniqueness as well

validates :user_name, :presence => true, :uniqueness => {:scope => :account_id}


# the old way  
validates_uniqueness_of :user_name, :scope => :account_id

Custom validator with i18n support

himn1 · Oct 6, 20102 thanks

Here is modified EmailValidator from the example above:

class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
  record.errors.add(attribute, options[:message] || :email) unless
    value =~ /\\A([^@\\s]+)@((?:[-a-z0-9]+\\.)+[a-z]{2,})\\z/i
end
end

And locale:

en:
activerecord:
  errors:
    messages:
      email: "is not an email"

Changing the Message

edivandecastro · Jul 20, 20122 thanks

For Change the default message:

==== Code example

validates :invoice_number, :presence => {:message => 'The invoice number must be informed.'}

validating a database column acceptance

korin · Jun 16, 20111 thank

+accept+ option should be set to +true+ if you are validating a database column, since the attribute is typecast from "1" to +true+ before validation

validates :terms,
acceptance: {
  allow_nil: false,
  accept: true
}

Common Validator options

nhance · Jul 1, 2011

Most validators will support all of the following common options: (Through ActiveModel::Errors::CALLBACK_OPTIONS (http://apidock.com/rails/ActiveModel/Errors))

  • :if
  • :unless
  • :allow_blank
  • :allow_nil

Example of conditions using

Graffzon · Mar 5, 2012

==== f.e. validates :number, :presence => { :if => :quota_file? }

def self.quota_file?
quota_file?
end

attributes that have the same names as options

nicb · Nov 6, 2012

For reasons that are beyond my comprehension, this piece of code

class Working

include ActiveModel::Validations

attr_accessor :format

validates :format, :presence => true, :format => { :with => /\\AWorking/ }

end

works (NOTE: it has an attribute that has the same name of an option), while this

class NotWorking < ActiveRecord::Base

validates :format, :presence => true, :format => { :with => /\\ANot Working/ }

end

does not (assuming that you have a legacy db in which you can't change the names of the columns). It throws an ArgumentError at you. However, a crude hack is to add an explicit accessor to the :format method, like this

class WorkingAgain < ActiveRecord::Base

validates :format, :presence => true, :format => { :with => /\\AWorking again/ }

def format
  read_attribute(:format)
end

end

Any explanation is welcome.