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 CommentincludeActiveModel::Validationsvalidate:must_be_friendsdef must_be_friendserrors.add(:base,'Must be friends to leave a comment')unlesscommenter.friend_of?(commentee)endend
With a block which is passed with the current record to be validated:
class CommentincludeActiveModel::Validationsvalidatedo|comment|comment.must_be_friendsenddef must_be_friendserrors.add(:base,'Must be friends to leave a comment')unlesscommenter.friend_of?(commentee)endend
Or with a block where self points to the current record to be
validated:
class CommentincludeActiveModel::Validationsvalidatedoerrors.add(:base,'Must be friends to leave a comment')unlesscommenter.friend_of?(commentee)endend
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.
NOTE: Calling validate
multiple times on the same method will overwrite previous definitions.
# File activemodel/lib/active_model/validations.rb, line 171
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.merge(if: [predicate_for_validation_context(options[:on]), *options[:if]])
end
set_callback(:validate, *args, options, &block)
end
# 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}>
# # ]
def validators
_validators.values.flatten.uniq
end
# 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 <tt>Person.clear_validators!</tt> and then checks to see what
# validators this class has, you would obtain:
#
# Person.validators # => []
#
# Also, the callback set by <tt>validate :cannot_be_robot</tt> will be erased
# so that:
#
# Person._validate_callbacks.empty? # => true
#
def clear_validators!
reset_callbacks(:validate)
_validators.clear
end
# 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={}>,
# # ]
def validators_on(*attributes)
attributes.flat_map do |attribute|
_validators[attribute.to_sym]
end
end
# 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
def attribute_method?(attribute)
method_defined?(attribute)
end
# Copy validators on inheritance.
def inherited(base) # :nodoc:
dup = _validators.dup
base._validators = dup.each { |k, v| dup[k] = v.dup }
super
end
private
@@predicates_for_validation_contexts = {}
def predicate_for_validation_context(context)
context = context.is_a?(Array) ? context.sort : Array(context)
@@predicates_for_validation_contexts[context] ||= -> (model) do
if model.validation_context.is_a?(Array)
model.validation_context.any? { |model_context| context.include?(model_context) }
else
context.include?(model.validation_context)
end
end
end
end
2Notes
Typo in example above
nhance · Jun 28, 2011
You aren't mistaken. That is an error in the example with the block above. There's an extra '(' character.
Accepted parameters for validate
ggarnier · May 28, 2012
Validate method also accepts +:on+ and +:if+ parameters. The default value for +:on+ is +:save+, the other accepted values are +:create+ and +:update+
class Comment
include ActiveModel::Validations
validate :must_be_friends, :on => :create, :if => Proc.new {|comment| some_condition}
def must_be_friends
errors.add(:base, "Must be friends to leave a comment") unless commenter.friend_of?(commentee)
end
end