# module ActiveModel::Validations::ClassMethods

### Public Instance Methods

attribute_method?(attribute) click to toggle source

Returns `true` if `attribute` is an attribute method, `false` otherwise.

    class Person
      include ActiveModel::Validations

      attr_accessor :name
    end

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

    # File lib/active_model/validations.rb, line 268
    def attribute_method?(attribute)
      method_defined?(attribute)
    end

clear_validators!() click to toggle source

Clears all of the validators and validations.

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

    class Person
      include ActiveModel::Validations

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

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

    Person.validators
    # => [
    #      #<MyValidator:0x007fbff403e808 @options={}>,
    #      #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
    #      #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
    #    ]

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

    Person.validators # => []

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

    Person._validate_callbacks.empty?  # => true

    # File lib/active_model/validations.rb, line 232
    def clear_validators!
      reset_callbacks(:validate)
      _validators.clear
    end

validate(*args, &block) click to toggle source

Adds a validation method or block to the class. This is useful when overriding the `validate` instance method becomes too unwieldy and you're looking for more descriptive declaration of your validations.

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

    class Comment
      include ActiveModel::Validations

      validate :must_be_friends

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

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

    class Comment
      include ActiveModel::Validations

      validate do |comment|
        comment.must_be_friends
      end

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

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

    class Comment
      include ActiveModel::Validations

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

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

Options:

- `:on` - Specifies the contexts where this validation is active. Runs in all validation contexts by default `nil`. You can pass a symbol or an array of symbols. (e.g. `on: :create` or `on: :custom_validation_context` or `on: [:create, :custom_validation_context]`)

- `: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.

    # File lib/active_model/validations.rb, line 150
    def validate(*args, &block)
      options = args.extract_options!

      if args.all? { |arg| arg.is_a?(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[:if] = Array(options[:if])
        options[:if].unshift ->(o) {
          !(Array(options[:on]) & Array(o.validation_context)).empty?
        }
      end

      args << options
      set_callback(:validate, *args, &block)
    end

validates(*attributes) click to toggle source

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 the contexts where this validation is active. Runs in all validation contexts by default `nil`. You can pass a symbol or an array of symbols. (e.g. `on: :create` or `on: :custom_validation_context` or `on: [:create, :custom_validation_context]`)

- `: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.

- `:allow_nil` - Skip validation if the attribute is `nil`.

- `:allow_blank` - Skip validation if the attribute is blank.

- `: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

    # File lib/active_model/validations/validates.rb, line 104
    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|
        next unless options
        key = "#{key.to_s.camelize}Validator"

        begin
          validator = key.include?("::".freeze) ? key.constantize : const_get(key)
        rescue NameError
          raise ArgumentError, "Unknown validator: '#{key}'"
        end

        validates_with(validator, defaults.merge(_parse_validates_options(options)))
      end
    end

validates!(*attributes) click to toggle source

This method is used to define validations that cannot be corrected by end users and are considered exceptional. So each validator defined with bang or `:strict` option set to `true` will always raise `ActiveModel::StrictValidationFailed` instead of adding error when validation fails. See `validates` for more information about the validation itself.

    class Person
      include ActiveModel::Validations

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

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

    # File lib/active_model/validations/validates.rb, line 145
    def validates!(*attributes)
      options = attributes.extract_options!
      options[:strict] = true
      validates(*(attributes << options))
    end

validates_each(*attr_names, &block) click to toggle source

Validates each attribute against a block.

    class Person
      include ActiveModel::Validations

      attr_accessor :first_name, :last_name

      validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|
        record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
      end
    end

Options:

- `:on` - Specifies the contexts where this validation is active. Runs in all validation contexts by default `nil`. You can pass a symbol or an array of symbols. (e.g. `on: :create` or `on: :custom_validation_context` or `on: [:create, :custom_validation_context]`)

- `:allow_nil` - Skip validation if attribute is `nil`.

- `:allow_blank` - Skip validation if attribute is blank.

- `: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.

    # File lib/active_model/validations.rb, line 86
    def validates_each(*attr_names, &block)
      validates_with BlockValidator, _merge_attributes(attr_names), &block
    end

validates_with(*args, &block) click to toggle source

Passes the record off to the class or classes specified and allows them to add errors based on more complex conditions.

    class Person
      include ActiveModel::Validations
      validates_with MyValidator
    end

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

      private
        def some_complex_logic
          # ...
        end
    end

You may also pass it multiple classes, like so:

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

Configuration options:

- `:on` - Specifies the contexts where this validation is active. Runs in all validation contexts by default `nil`. You can pass a symbol or an array of symbols. (e.g. `on: :create` or `on: :custom_validation_context` or `on: [:create, :custom_validation_context]`)

- `: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` - Specifies whether validation should be strict. See `ActiveModel::Validations#validates!` for more information.

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

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

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

    # File lib/active_model/validations/with.rb, line 79
    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

validators() click to toggle source

List all validators that are being used to validate the model using `validates_with` method.

    class Person
      include ActiveModel::Validations

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

    Person.validators
    # => [
    #      #<MyValidator:0x007fbff403e808 @options={}>,
    #      #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
    #      #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
    #    ]

    # File lib/active_model/validations.rb, line 190
    def validators
      _validators.values.flatten.uniq
    end

validators_on(*attributes) click to toggle source

List all validators that are being used to validate a specific attribute.

    class Person
      include ActiveModel::Validations

      attr_accessor :name , :age

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

    Person.validators_on(:name)
    # => [
    #       #<ActiveModel::Validations::PresenceValidator:0x007fe604914e60 @attributes=[:name], @options={}>,
    #    ]

    # File lib/active_model/validations.rb, line 252
    def validators_on(*attributes)
      attributes.flat_map do |attribute|
        _validators[attribute.to_sym]
      end
    end

### Private Instance Methods

_parse_validates_options(options) click to toggle source

    # File lib/active_model/validations/validates.rb, line 159
    def _parse_validates_options(options)
      case options
      when TrueClass
        {}
      when Hash
        options
      when Range, Array
        { in: options }
      else
        { with: options }
      end
    end

_validates_default_keys() click to toggle source

When creating custom validators, it might be useful to be able to specify additional default keys. This can be done by overwriting this method.

    # File lib/active_model/validations/validates.rb, line 155
    def _validates_default_keys
      [:if, :unless, :on, :allow_blank, :allow_nil , :strict]
    end