Module: ActiveModel::Validations::ClassMethods

Defined in:
activemodel/lib/active_model/validations.rb,
activemodel/lib/active_model/validations/with.rb,
activemodel/lib/active_model/validations/validates.rb

Instance Method Summary collapse

Instance Method Details

#attribute_method?(attribute) ⇒ Boolean

Check if method is an attribute method or not.



156
157
158
# File 'activemodel/lib/active_model/validations.rb', line 156

def attribute_method?(attribute)
  method_defined?(attribute)
end

#inherited(base) ⇒ Object

Copy validators on inheritance.



161
162
163
164
165
# File 'activemodel/lib/active_model/validations.rb', line 161

def inherited(base)
  dup = _validators.dup
  base._validators = dup.each { |k, v| dup[k] = v.dup }
  super
end

#validate(*args, &block) ⇒ Object

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_to_base("Must be friends to leave a comment") unless commenter.friend_of?(commentee)
  end
end

Or 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_to_base("Must be friends to leave a comment") unless commenter.friend_of?(commentee)
  end
end


121
122
123
124
125
126
127
128
129
130
# File 'activemodel/lib/active_model/validations.rb', line 121

def validate(*args, &block)
  options = args.extract_options!
  if options.key?(:on)
    options = options.dup
    options[:if] = Array.wrap(options[:if])
    options[:if] << "validation_context == :#{options[:on]}"
  end
  args << options
  set_callback(:validate, *args, &block)
end

#validates(*attributes) ⇒ Object

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 e.g.

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.errors[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 e.g.

class Film
  include ActiveModel::Validations

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

  validates :name, :title => true
end

The validators hash can also handle regular expressions, ranges and arrays:

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

Finally, the options :if, :unless, :on, :allow_blank and :allow_nil can be given to one specific validator:

validates :password, :presence => { :if => :password_required? }, :confirmation => true

Or to all at the same time:

validates :password, :presence => true, :confirmation => true, :if => :password_required?

Raises:

  • (ArgumentError)


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'activemodel/lib/active_model/validations/validates.rb', line 73

def validates(*attributes)
  defaults = attributes.extract_options!
  validations = defaults.slice!(:if, :unless, :on, :allow_blank, :allow_nil)

  raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
  raise ArgumentError, "Attribute names must be symbols" if attributes.any?{ |attribute| !attribute.is_a?(Symbol) }
  raise ArgumentError, "You need to supply at least one validation" if validations.empty?

  defaults.merge!(:attributes => attributes)

  validations.each do |key, options|
    begin
      validator = const_get("#{key.to_s.camelize}Validator")
    rescue NameError
      raise ArgumentError, "Unknown validator: '#{key}'"
    end

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

#validates_each(*attr_names, &block) ⇒ Object

Validates each attribute against a block.

class Person
  include ActiveModel::Validations

  attr_accessor :first_name, :last_name

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

Options:

  • :on - Specifies when this validation is active (default is :save, other options :create, :update).

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



86
87
88
89
# File 'activemodel/lib/active_model/validations.rb', line 86

def validates_each(*attr_names, &block)
  options = attr_names.extract_options!.symbolize_keys
  validates_with BlockValidator, options.merge(:attributes => attr_names.flatten), &block
end

#validates_with(*args, &block) ⇒ Object

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[: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 when this validation is active (:create or :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.

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


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'activemodel/lib/active_model/validations/with.rb', line 67

def validates_with(*args, &block)
  options = args.extract_options!
  args.each do |klass|
    validator = klass.new(options, &block)
    validator.setup(self) if validator.respond_to?(:setup)

    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

#validatorsObject

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



146
147
148
# File 'activemodel/lib/active_model/validations.rb', line 146

def validators
  _validators.values.flatten.uniq
end

#validators_on(attribute) ⇒ Object

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



151
152
153
# File 'activemodel/lib/active_model/validations.rb', line 151

def validators_on(attribute)
  _validators[attribute.to_sym]
end