module ActiveModel::Validations::ClassMethods

def _parse_validates_options(options)

def _parse_validates_options(options)
  case options
  when TrueClass
    {}
  when Hash
    options
  when Range, Array
    { in: options }
  else
    { with: options }
  end
end

def _validates_default_keys

additional default keys. This can be done by overwriting this method.
When creating custom validators, it might be useful to be able to specify
def _validates_default_keys
  [:if, :unless, :on, :allow_blank, :allow_nil, :strict]
end

def attribute_method?(attribute)

User.attribute_method?(:age) # => false
User.attribute_method?(:name) # => true

end
attr_accessor :name

include ActiveModel::Validations
class Person

Returns +true+ if +attribute+ is an attribute method, +false+ otherwise.
def attribute_method?(attribute)
  method_defined?(attribute)
end

def clear_validators!


Person._validate_callbacks.empty? # => true

so that:
Also, the callback set by validate :cannot_be_robot will be erased

Person.validators # => []

validators this class has, you would obtain:
If one runs Person.clear_validators! and then checks to see what

# ]
# #
# #,
# #,
# => [
Person.validators

end
end
errors.add(:base, 'A person cannot be a robot') if person_is_robot
def cannot_be_robot

validate :cannot_be_robot
validates_with StrictValidator, strict: true
validates_with OtherValidator, on: :create
validates_with MyValidator

include ActiveModel::Validations
class Person

of +validate+.
+validates_with+ and the callbacks that are set by an invocation
It clears the validators that are created with an invocation of
the model for both the +validates_with+ and +validate+ methods.
Note that this will clear anything that is being used to validate

Clears all of the validators and validations.
def clear_validators!
  reset_callbacks(:validate)
  _validators.clear
end

def inherited(base) # :nodoc:

:nodoc:
Copy validators on inheritance.
def inherited(base) # :nodoc:
  dup = _validators.dup
  base._validators = dup.each { |k, v| dup[k] = v.dup }
  super
end

def validate(*args, &block)


NOTE: Calling +validate+ multiple times on the same method will overwrite previous definitions.

value.
method, proc, or string should return or evaluate to a +true+ or +false+
or unless: Proc.new { |user| user.signup_step <= 2 }). The
determine if the validation should not occur (e.g. unless: :skip_validation,
* :unless - Specifies a method, proc, or string to call to
proc or string should return or evaluate to a +true+ or +false+ value.
or if: Proc.new { |user| user.signup_step > 2 }). The method,
if the validation should occur (e.g. if: :allow_validation,
* :if - Specifies a method, proc, or string to call to determine
on: [:create, :custom_validation_context])
on: :custom_validation_context or
or an array of symbols. (e.g. on: :create or
Runs in all validation contexts by default +nil+. You can pass a symbol
* :on - Specifies the contexts where this validation is active.
Options:

It's not possible to halt the validate callback chain.
Note that the return value of validation methods is not relevant.

end
end
errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
validate do

include ActiveModel::Validations
class Comment

Or with a block where +self+ points to the current record to be validated:

end
end
errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
def must_be_friends

end
comment.must_be_friends
validate do |comment|

include ActiveModel::Validations
class Comment

With a block which is passed with the current record to be validated:

end
end
errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
def must_be_friends

validate :must_be_friends

include ActiveModel::Validations
class Comment

This can be done with a symbol pointing to a method:

you're looking for more descriptive declaration of your validations.
overriding the +validate+ instance method becomes too unwieldy and
Adds a validation method or block to the class. This is useful when
def validate(*args, &block)
  options = args.extract_options!
  if args.all?(Symbol)
    options.each_key do |k|
      unless VALID_OPTIONS_FOR_VALIDATE.include?(k)
        raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{VALID_OPTIONS_FOR_VALIDATE.map(&:inspect).join(', ')}. Perhaps you meant to call `validates` instead of `validate`?")
      end
    end
  end
  if options.key?(:on)
    options = options.dup
    options[:on] = Array(options[:on])
    options[:if] = [
      ->(o) { !(options[:on] & Array(o.validation_context)).empty? },
      *options[:if]
    ]
  end
  set_callback(:validate, *args, options, &block)
end

def validates(*attributes)

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

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


validates :token, length: 24, strict: TokenLengthException
validates :password, presence: true, confirmation: true, if: :password_required?

Example:

:strict option can also be set to any other exception.
will raise ActiveModel::StrictValidationFailed instead of adding the error.
* :strict - If the :strict option is set to true
* :allow_blank - Skip validation if the attribute is blank.
* :allow_nil - Skip validation if the attribute is +nil+.
+false+ value.
method, proc, or string should return or evaluate to a +true+ or
or unless: Proc.new { |user| user.signup_step <= 2 }). The
if the validation should not occur (e.g. unless: :skip_validation,
* :unless - Specifies a method, proc, or string to call to determine
proc or string should return or evaluate to a +true+ or +false+ value.
or if: Proc.new { |user| user.signup_step > 2 }). The method,
if the validation should occur (e.g. if: :allow_validation,
* :if - Specifies a method, proc, or string to call to determine
on: [:create, :custom_validation_context])
on: :custom_validation_context or
or an array of symbols. (e.g. on: :create or
Runs in all validation contexts by default +nil+. You can pass a symbol
* :on - Specifies the contexts where this validation is active.

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

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

validates :password, length: 6..20
validates :role, inclusion: %w(admin contributor)
validates :email, format: /@/

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

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

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

end
validates :name, title: true

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

include ActiveModel::Validations
class Film

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

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

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

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

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

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

Examples of using the default rails validators:

custom validator classes in their place such as PresenceValidator.
validators can be overridden inside specific classes by creating
validator classes ending in 'Validator'. Note that Rails default
This method is a shortcut to all default validators and any custom
def validates(*attributes)
  defaults = attributes.extract_options!.dup
  validations = defaults.slice!(*_validates_default_keys)
  raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
  raise ArgumentError, "You need to supply at least one validation" if validations.empty?
  defaults[:attributes] = attributes
  validations.each do |key, options|
    key = "#{key.to_s.camelize}Validator"
    begin
      validator = key.include?("::") ? key.constantize : const_get(key)
    rescue NameError
      raise ArgumentError, "Unknown validator: '#{key}'"
    end
    next unless options
    validates_with(validator, defaults.merge(_parse_validates_options(options)))
  end
end

def validates!(*attributes)

# => ActiveModel::StrictValidationFailed: Name can't be blank
person.valid?
person.name = ''
person = Person.new

end
validates! :name, presence: true
attr_accessor :name

include ActiveModel::Validations
class Person

the validation itself.
when validation fails. See validates for more information about
ActiveModel::StrictValidationFailed instead of adding error
or :strict option set to true will always raise
users and are considered exceptional. So each validator defined with bang
This method is used to define validations that cannot be corrected by end
def validates!(*attributes)
  options = attributes.extract_options!
  options[:strict] = true
  validates(*(attributes << options))
end

def validates_each(*attr_names, &block)

value.
method, proc, or string should return or evaluate to a +true+ or +false+
or unless: Proc.new { |user| user.signup_step <= 2 }). The
determine if the validation should not occur (e.g. unless: :skip_validation,
* :unless - Specifies a method, proc, or string to call to
proc or string should return or evaluate to a +true+ or +false+ value.
or if: Proc.new { |user| user.signup_step > 2 }). The method,
if the validation should occur (e.g. if: :allow_validation,
* :if - Specifies a method, proc, or string to call to determine
* :allow_blank - Skip validation if attribute is blank.
* :allow_nil - Skip validation if attribute is +nil+.
on: [:create, :custom_validation_context])
on: :custom_validation_context or
or an array of symbols. (e.g. on: :create or
Runs in all validation contexts by default +nil+. You can pass a symbol
* :on - Specifies the contexts where this validation is active.
Options:

end
end
record.errors.add attr, "starts with z." if value.start_with?("z")
validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|

attr_accessor :first_name, :last_name

include ActiveModel::Validations
class Person

Validates each attribute against a block.
def validates_each(*attr_names, &block)
  validates_with BlockValidator, _merge_attributes(attr_names), &block
end

def validates_with(*args, &block)

end
end
options[:my_custom_key] # => "my custom value"
def validate(record)
class MyValidator < ActiveModel::Validator

end
validates_with MyValidator, my_custom_key: 'my custom value'
include ActiveModel::Validations
class Person

to the class and available as +options+:
If you pass any additional configuration options, they will be passed

See ActiveModel::Validations#validates! for more information.
* :strict - Specifies whether validation should be strict.
+false+ value.
The method, proc, or string should return or evaluate to a +true+ or
unless: Proc.new { |user| user.signup_step <= 2 }).
(e.g. unless: :skip_validation, or
determine if the validation should not occur
* :unless - Specifies a method, proc, or string to call to
+false+ value.
The method, proc, or string should return or evaluate to a +true+ or
or if: Proc.new { |user| user.signup_step > 2 }).
if the validation should occur (e.g. if: :allow_validation,
* :if - Specifies a method, proc, or string to call to determine
on: [:create, :custom_validation_context])
on: :custom_validation_context or
or an array of symbols. (e.g. on: :create or
Runs in all validation contexts by default +nil+. You can pass a symbol
* :on - Specifies the contexts where this validation is active.
Configuration options:

end
validates_with MyValidator, MyOtherValidator, on: :create
include ActiveModel::Validations
class Person

You may also pass it multiple classes, like so:

end
end
# ...
def some_complex_logic
private

end
end
record.errors.add :base, 'This record is invalid'
if some_complex_logic
def validate(record)
class MyValidator < ActiveModel::Validator

end
validates_with MyValidator
include ActiveModel::Validations
class Person

to add errors based on more complex conditions.
Passes the record off to the class or classes specified and allows them
def validates_with(*args, &block)
  options = args.extract_options!
  options[:class] = self
  args.each do |klass|
    validator = klass.new(options, &block)
    if validator.respond_to?(:attributes) && !validator.attributes.empty?
      validator.attributes.each do |attribute|
        _validators[attribute.to_sym] << validator
      end
    else
      _validators[nil] << validator
    end
    validate(validator, options)
  end
end

def validators

# ]
# #
# #,
# #,
# => [
Person.validators

end
validates_with StrictValidator, strict: true
validates_with OtherValidator, on: :create
validates_with MyValidator

include ActiveModel::Validations
class Person

+validates_with+ method.
List all validators that are being used to validate the model using
def validators
  _validators.values.flatten.uniq
end

def validators_on(*attributes)

# ]
# #,
# => [
Person.validators_on(:name)

end
validates_inclusion_of :age, in: 0..99
validates_presence_of :name

attr_accessor :name, :age

include ActiveModel::Validations
class Person

List all validators that are being used to validate a specific attribute.
def validators_on(*attributes)
  attributes.flat_map do |attribute|
    _validators[attribute.to_sym]
  end
end