Methods
- attribute_method?
- clear_validators!
- validate
- validates
- validates!
- validates_each
- validates_with
- validators
- validators_on
Instance Public methods
attribute_method?(attribute)
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
📝 Source code
# File activemodel/lib/active_model/validations.rb, line 272
def attribute_method?(attribute)
method_defined?(attribute)
end
🔎 See on GitHub
clear_validators!()
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
📝 Source code
# File activemodel/lib/active_model/validations.rb, line 236
def clear_validators!
reset_callbacks(:validate)
_validators.clear
end
🔎 See on GitHub
validate(*args, &block)
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 defaultnil
. You can pass a symbol or an array of symbols. (e.g.on: :create
oron: :custom_validation_context
oron: [: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
, orif: Proc.new { |user| user.signup_step > 2 }
). The method, proc or string should return or evaluate to atrue
orfalse
value. -
:unless
- Specifies a method, proc or string to call to determine if the validation should not occur (e.g.unless: :skip_validation
, orunless: Proc.new { |user| user.signup_step <= 2 }
). The method, proc or string should return or evaluate to atrue
orfalse
value.
NOTE: Calling validate
multiple times on the same method will overwrite previous definitions.
📝 Source code
# File activemodel/lib/active_model/validations.rb, line 154
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[:on] = Array(options[:on])
options[:if] = Array(options[:if])
options[:if].unshift ->(o) {
!(options[:on] & Array(o.validation_context)).empty?
}
end
set_callback(:validate, *args, options, &block)
end
🔎 See on GitHub
validates(*attributes)
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
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, 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 defaultnil
. You can pass a symbol or an array of symbols. (e.g.on: :create
oron: :custom_validation_context
oron: [: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
, orif: Proc.new { |user| user.signup_step > 2 }
). The method, proc or string should return or evaluate to atrue
orfalse
value. -
:unless
- Specifies a method, proc or string to call to determine if the validation should not occur (e.g.unless: :skip_validation
, orunless: Proc.new { |user| user.signup_step <= 2 }
). The method, proc or string should return or evaluate to atrue
orfalse
value. -
:allow_nil
- Skip validation if the attribute isnil
. -
:allow_blank
- Skip validation if the attribute is blank. -
:strict
- If the:strict
option is set to true will raiseActiveModel::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, length: 24, strict: TokenLengthException
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
📝 Source code
# File activemodel/lib/active_model/validations/validates.rb, line 105
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
🔎 See on GitHub
validates!(*attributes)
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
📝 Source code
# File activemodel/lib/active_model/validations/validates.rb, line 146
def validates!(*attributes)
options = attributes.extract_options!
options[:strict] = true
validates(*(attributes << options))
end
🔎 See on GitHub
validates_each(*attr_names, &block)
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 defaultnil
. You can pass a symbol or an array of symbols. (e.g.on: :create
oron: :custom_validation_context
oron: [:create, :custom_validation_context]
) -
:allow_nil
- Skip validation if attribute isnil
. -
: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
, orif: Proc.new { |user| user.signup_step > 2 }
). The method, proc or string should return or evaluate to atrue
orfalse
value. -
:unless
- Specifies a method, proc or string to call to determine if the validation should not occur (e.g.unless: :skip_validation
, orunless: Proc.new { |user| user.signup_step <= 2 }
). The method, proc or string should return or evaluate to atrue
orfalse
value.
📝 Source code
# File activemodel/lib/active_model/validations.rb, line 87
def validates_each(*attr_names, &block)
validates_with BlockValidator, _merge_attributes(attr_names), &block
end
🔎 See on GitHub
validates_with(*args, &block)
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 defaultnil
. You can pass a symbol or an array of symbols. (e.g.on: :create
oron: :custom_validation_context
oron: [: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
, orif: Proc.new { |user| user.signup_step > 2 }
). The method, proc or string should return or evaluate to atrue
orfalse
value. -
:unless
- Specifies a method, proc or string to call to determine if the validation should not occur (e.g.unless: :skip_validation
, orunless: Proc.new { |user| user.signup_step <= 2 }
). The method, proc or string should return or evaluate to atrue
orfalse
value. -
:strict
- Specifies whether validation should be strict. SeeActiveModel::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
📝 Source code
# File activemodel/lib/active_model/validations/with.rb, line 81
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
🔎 See on GitHub
validators()
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}>
# ]
📝 Source code
# File activemodel/lib/active_model/validations.rb, line 194
def validators
_validators.values.flatten.uniq
end
🔎 See on GitHub
validators_on(*attributes)
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={}>,
# ]
📝 Source code
# File activemodel/lib/active_model/validations.rb, line 256
def validators_on(*attributes)
attributes.flat_map do |attribute|
_validators[attribute.to_sym]
end
end
🔎 See on GitHub