aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib/active_model/validations
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/lib/active_model/validations')
-rw-r--r--activemodel/lib/active_model/validations/acceptance.rb30
-rw-r--r--activemodel/lib/active_model/validations/callbacks.rb86
-rw-r--r--activemodel/lib/active_model/validations/clusivity.rb41
-rw-r--r--activemodel/lib/active_model/validations/confirmation.rb34
-rw-r--r--activemodel/lib/active_model/validations/exclusion.rb74
-rw-r--r--activemodel/lib/active_model/validations/format.rb78
-rw-r--r--activemodel/lib/active_model/validations/inclusion.rb71
-rw-r--r--activemodel/lib/active_model/validations/length.rb71
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb62
-rw-r--r--activemodel/lib/active_model/validations/presence.rb28
-rw-r--r--activemodel/lib/active_model/validations/validates.rb93
-rw-r--r--activemodel/lib/active_model/validations/with.rb54
12 files changed, 407 insertions, 315 deletions
diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb
index e628c6f306..8d5ebf527f 100644
--- a/activemodel/lib/active_model/validations/acceptance.rb
+++ b/activemodel/lib/active_model/validations/acceptance.rb
@@ -2,9 +2,9 @@ module ActiveModel
# == Active Model Acceptance Validator
module Validations
- class AcceptanceValidator < EachValidator
+ class AcceptanceValidator < EachValidator #:nodoc:
def initialize(options)
- super(options.reverse_merge(:allow_nil => true, :accept => "1"))
+ super({ :allow_nil => true, :accept => "1" }.merge!(options))
end
def validate_each(record, attribute, value)
@@ -23,11 +23,11 @@ module ActiveModel
module HelperMethods
# Encapsulates the pattern of wanting to validate the acceptance of a
- # terms of service check box (or similar agreement). Example:
+ # terms of service check box (or similar agreement).
#
# class Person < ActiveRecord::Base
# validates_acceptance_of :terms_of_service
- # validates_acceptance_of :eula, :message => "must be abided"
+ # validates_acceptance_of :eula, message: "must be abided"
# end
#
# If the database column does not exist, the +terms_of_service+ attribute
@@ -37,29 +37,17 @@ module ActiveModel
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "must be
# accepted").
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
- # and <tt>:update</tt>.
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default
- # is true).
+ # is +true+).
# * <tt>:accept</tt> - Specifies value that is considered accepted.
# The default value is a string "1", which makes it easy to relate to
# an HTML checkbox. This should be set to +true+ if you are validating
# a database column, since the attribute is typecast from "1" to +true+
# before validation.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
- # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
- # or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false
- # value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to
- # determine if the validation should not occur (for example,
- # <tt>:unless => :skip_validation</tt>, or
- # <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or
- # false value.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ #
+ # There is also a list of default options supported by every validator:
+ # +:if+, +:unless+, +:on+ and +:strict+.
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
def validates_acceptance_of(*attr_names)
validates_with AcceptanceValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/callbacks.rb b/activemodel/lib/active_model/validations/callbacks.rb
index c39c85e1af..bf3fe7ff04 100644
--- a/activemodel/lib/active_model/validations/callbacks.rb
+++ b/activemodel/lib/active_model/validations/callbacks.rb
@@ -2,23 +2,24 @@ require 'active_support/callbacks'
module ActiveModel
module Validations
+ # == Active Model Validation callbacks
+ #
+ # Provides an interface for any class to have +before_validation+ and
+ # +after_validation+ callbacks.
+ #
+ # First, include ActiveModel::Validations::Callbacks from the class you are
+ # creating:
+ #
+ # class MyModel
+ # include ActiveModel::Validations::Callbacks
+ #
+ # before_validation :do_stuff_before_validation
+ # after_validation :do_stuff_after_validation
+ # end
+ #
+ # Like other <tt>before_*</tt> callbacks if +before_validation+ returns
+ # +false+ then <tt>valid?</tt> will not be called.
module Callbacks
- # == Active Model Validation callbacks
- #
- # Provides an interface for any class to have <tt>before_validation</tt> and
- # <tt>after_validation</tt> callbacks.
- #
- # First, extend ActiveModel::Callbacks from the class you are creating:
- #
- # class MyModel
- # include ActiveModel::Validations::Callbacks
- #
- # before_validation :do_stuff_before_validation
- # after_validation :do_stuff_after_validation
- # end
- #
- # Like other before_* callbacks if <tt>before_validation</tt> returns false
- # then <tt>valid?</tt> will not be called.
extend ActiveSupport::Concern
included do
@@ -27,6 +28,30 @@ module ActiveModel
end
module ClassMethods
+ # Defines a callback that will get called right before validation
+ # happens.
+ #
+ # class Person
+ # include ActiveModel::Validations
+ # include ActiveModel::Validations::Callbacks
+ #
+ # attr_accessor :name
+ #
+ # validates_length_of :name, maximum: 6
+ #
+ # before_validation :remove_whitespaces
+ #
+ # private
+ #
+ # def remove_whitespaces
+ # name.strip!
+ # end
+ # end
+ #
+ # person = Person.new
+ # person.name = ' bob '
+ # person.valid? # => true
+ # person.name # => "bob"
def before_validation(*args, &block)
options = args.last
if options.is_a?(Hash) && options[:on]
@@ -36,6 +61,33 @@ module ActiveModel
set_callback(:validation, :before, *args, &block)
end
+ # Defines a callback that will get called right after validation
+ # happens.
+ #
+ # class Person
+ # include ActiveModel::Validations
+ # include ActiveModel::Validations::Callbacks
+ #
+ # attr_accessor :name, :status
+ #
+ # validates_presence_of :name
+ #
+ # after_validation :set_status
+ #
+ # private
+ #
+ # def set_status
+ # self.status = errors.empty?
+ # end
+ # end
+ #
+ # person = Person.new
+ # person.name = ''
+ # person.valid? # => false
+ # person.status # => false
+ #  person.name = 'bob'
+ # person.valid? # => true
+ # person.status # => true
def after_validation(*args, &block)
options = args.extract_options!
options[:prepend] = true
@@ -48,7 +100,7 @@ module ActiveModel
protected
# Overwrite run validations to include callbacks.
- def run_validations!
+ def run_validations! #:nodoc:
run_callbacks(:validation) { super }
end
end
diff --git a/activemodel/lib/active_model/validations/clusivity.rb b/activemodel/lib/active_model/validations/clusivity.rb
new file mode 100644
index 0000000000..cf1415b6c2
--- /dev/null
+++ b/activemodel/lib/active_model/validations/clusivity.rb
@@ -0,0 +1,41 @@
+require 'active_support/core_ext/range.rb'
+
+module ActiveModel
+ module Validations
+ module Clusivity #:nodoc:
+ ERROR_MESSAGE = "An object with the method #include? or a proc, lambda or symbol is required, " <<
+ "and must be supplied as the :in (or :within) option of the configuration hash"
+
+ def check_validity!
+ unless delimiter.respond_to?(:include?) || delimiter.respond_to?(:call) || delimiter.respond_to?(:to_sym)
+ raise ArgumentError, ERROR_MESSAGE
+ end
+ end
+
+ private
+
+ def include?(record, value)
+ exclusions = if delimiter.respond_to?(:call)
+ delimiter.call(record)
+ elsif delimiter.respond_to?(:to_sym)
+ record.send(delimiter)
+ else
+ delimiter
+ end
+
+ exclusions.send(inclusion_method(exclusions), value)
+ end
+
+ def delimiter
+ @delimiter ||= options[:in] || options[:within]
+ end
+
+ # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
+ # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
+ # uses the previous logic of comparing a value with the range endpoints.
+ def inclusion_method(enumerable)
+ enumerable.is_a?(Range) ? :cover? : :include?
+ end
+ end
+ end
+end
diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb
index e8526303e2..baa034eca6 100644
--- a/activemodel/lib/active_model/validations/confirmation.rb
+++ b/activemodel/lib/active_model/validations/confirmation.rb
@@ -2,10 +2,11 @@ module ActiveModel
# == Active Model Confirmation Validator
module Validations
- class ConfirmationValidator < EachValidator
+ class ConfirmationValidator < EachValidator #:nodoc:
def validate_each(record, attribute, value)
if (confirmed = record.send("#{attribute}_confirmation")) && (value != confirmed)
- record.errors.add(attribute, :confirmation, options)
+ human_attribute_name = record.class.human_attribute_name(attribute)
+ record.errors.add(:"#{attribute}_confirmation", :confirmation, options.merge(:attribute => human_attribute_name))
end
end
@@ -18,13 +19,13 @@ module ActiveModel
module HelperMethods
# Encapsulates the pattern of wanting to validate a password or email
- # address field with a confirmation. For example:
+ # address field with a confirmation.
#
# Model:
# class Person < ActiveRecord::Base
# validates_confirmation_of :user_name, :password
# validates_confirmation_of :email_address,
- # :message => "should match confirmation"
+ # message: 'should match confirmation'
# end
#
# View:
@@ -37,29 +38,18 @@ module ActiveModel
# attribute.
#
# NOTE: This check is performed only if +password_confirmation+ is not
- # +nil+. To require confirmation, make sure
- # to add a presence check for the confirmation attribute:
+ # +nil+. To require confirmation, make sure to add a presence check for
+ # the confirmation attribute:
#
- # validates_presence_of :password_confirmation, :if => :password_changed?
+ # validates_presence_of :password_confirmation, if: :password_changed?
#
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "doesn't match
# confirmation").
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
- # and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
- # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
- # or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false
- # value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to
- # determine if the validation should not occur (e.g.
- # <tt>:unless => :skip_validation</tt>, or
- # <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ #
+ # There is also a list of default options supported by every validator:
+ # +:if+, +:unless+, +:on+ and +:strict+.
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
def validates_confirmation_of(*attr_names)
validates_with ConfirmationValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb
index 644cc814a7..3ec552c372 100644
--- a/activemodel/lib/active_model/validations/exclusion.rb
+++ b/activemodel/lib/active_model/validations/exclusion.rb
@@ -1,66 +1,48 @@
-require 'active_support/core_ext/range'
+require "active_model/validations/clusivity"
module ActiveModel
# == Active Model Exclusion Validator
module Validations
- class ExclusionValidator < EachValidator
- ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " <<
- "and must be supplied as the :in option of the configuration hash"
-
- def check_validity!
- unless [:include?, :call].any? { |method| options[:in].respond_to?(method) }
- raise ArgumentError, ERROR_MESSAGE
- end
- end
+ class ExclusionValidator < EachValidator #:nodoc:
+ include Clusivity
def validate_each(record, attribute, value)
- delimiter = options[:in]
- exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter
- if exclusions.send(inclusion_method(exclusions), value)
- record.errors.add(attribute, :exclusion, options.except(:in).merge!(:value => value))
+ if include?(record, value)
+ record.errors.add(attribute, :exclusion, options.except(:in, :within).merge!(:value => value))
end
end
-
- private
-
- # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
- # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
- # uses the previous logic of comparing a value with the range endpoints.
- def inclusion_method(enumerable)
- enumerable.is_a?(Range) ? :cover? : :include?
- end
end
module HelperMethods
- # Validates that the value of the specified attribute is not in a particular enumerable object.
+ # Validates that the value of the specified attribute is not in a
+ # particular enumerable object.
#
# class Person < ActiveRecord::Base
- # validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
- # validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
- # validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
- # validates_exclusion_of :password, :in => lambda { |p| [p.username, p.first_name] }, :message => "should not be the same as your username or first name"
+ # validates_exclusion_of :username, in: %w( admin superuser ), message: "You don't belong here"
+ # validates_exclusion_of :age, in: 30..60, message: 'This site is only for under 30 and over 60'
+ # validates_exclusion_of :format, in: %w( mov avi ), message: "extension %{value} is not allowed"
+ # validates_exclusion_of :password, in: ->(person) { [person.username, person.first_name] },
+ # message: 'should not be the same as your username or first name'
+ # validates_exclusion_of :karma, in: :reserved_karmas
# end
#
# Configuration options:
- # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of.
- # This can be supplied as a proc or lambda which returns an enumerable. If the enumerable
- # is a range the test is performed with <tt>Range#cover?</tt>
- # (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
- # and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # * <tt>:in</tt> - An enumerable object of items that the value shouldn't
+ # be part of. This can be supplied as a proc, lambda or symbol which returns an
+ # enumerable. If the enumerable is a range the test is performed with
+ # * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
+ # <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>.
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is
+ # reserved").
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the
+ # attribute is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
+ # attribute is blank(default is +false+).
+ #
+ # There is also a list of default options supported by every validator:
+ # +:if+, +:unless+, +:on+ and +:strict+.
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
def validates_exclusion_of(*attr_names)
validates_with ExclusionValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index d3faa8c6a6..80150229a0 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -2,7 +2,7 @@ module ActiveModel
# == Active Model Format Validator
module Validations
- class FormatValidator < EachValidator
+ class FormatValidator < EachValidator #:nodoc:
def validate_each(record, attribute, value)
if options[:with]
regexp = option_call(record, :with)
@@ -33,59 +33,81 @@ module ActiveModel
record.errors.add(attribute, :invalid, options.except(name).merge!(:value => value))
end
+ def regexp_using_multiline_anchors?(regexp)
+ regexp.source.start_with?("^") ||
+ (regexp.source.end_with?("$") && !regexp.source.end_with?("\\$"))
+ end
+
def check_options_validity(options, name)
option = options[name]
if option && !option.is_a?(Regexp) && !option.respond_to?(:call)
raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
+ elsif option && option.is_a?(Regexp) &&
+ regexp_using_multiline_anchors?(option) && options[:multiline] != true
+ raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \
+ "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \
+ ":multiline => true option?"
end
end
end
module HelperMethods
- # Validates whether the value of the specified attribute is of the correct form, going by the regular expression provided.
- # You can require that the attribute matches the regular expression:
+ # Validates whether the value of the specified attribute is of the correct
+ # form, going by the regular expression provided.You can require that the
+ # attribute matches the regular expression:
#
# class Person < ActiveRecord::Base
- # validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
+ # validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create
# end
#
- # Alternatively, you can require that the specified attribute does _not_ match the regular expression:
+ # Alternatively, you can require that the specified attribute does _not_
+ # match the regular expression:
#
# class Person < ActiveRecord::Base
- # validates_format_of :email, :without => /NOSPAM/
+ # validates_format_of :email, without: /NOSPAM/
# end
#
- # You can also provide a proc or lambda which will determine the regular expression that will be used to validate the attribute
+ # You can also provide a proc or lambda which will determine the regular
+ # expression that will be used to validate the attribute.
#
# class Person < ActiveRecord::Base
# # Admin can have number as a first letter in their screen name
- # validates_format_of :screen_name, :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i }
+ # validates_format_of :screen_name,
+ # with: ->(person) { person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i }
# end
#
- # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
+ # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the
+ # string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
#
- # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In addition, both must be a regular expression
- # or a proc or lambda, or else an exception will be raised.
+ # Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass
+ # the <tt>multiline: true</tt> option in case you use any of these two
+ # anchors in the provided regular expression. In most cases, you should be
+ # using <tt>\A</tt> and <tt>\z</tt>.
+ #
+ # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
+ # In addition, both must be a regular expression or a proc or lambda, or
+ # else an exception will be raised.
#
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
- # * <tt>:with</tt> - Regular expression that if the attribute matches will result in a successful validation.
- # This can be provided as a proc or lambda returning regular expression which will be called at runtime.
- # * <tt>:without</tt> - Regular expression that if the attribute does not match will result in a successful validation.
- # This can be provided as a proc or lambda returning regular expression which will be called at runtime.
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
- # and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the
+ # attribute is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
+ # attribute is blank (default is +false+).
+ # * <tt>:with</tt> - Regular expression that if the attribute matches will
+ # result in a successful validation. This can be provided as a proc or
+ # lambda returning regular expression which will be called at runtime.
+ # * <tt>:without</tt> - Regular expression that if the attribute does not
+ # match will result in a successful validation. This can be provided as
+ # a proc or lambda returning regular expression which will be called at
+ # runtime.
+ # * <tt>:multiline</tt> - Set to true if your regular expression contains
+ # anchors that match the beginning or end of lines as opposed to the
+ # beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>.
+ #
+ # There is also a list of default options supported by every validator:
+ # +:if+, +:unless+, +:on+ and +:strict+.
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
def validates_format_of(*attr_names)
validates_with FormatValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb
index 147e2ecb69..babc8982da 100644
--- a/activemodel/lib/active_model/validations/inclusion.rb
+++ b/activemodel/lib/active_model/validations/inclusion.rb
@@ -1,66 +1,47 @@
-require 'active_support/core_ext/range'
+require "active_model/validations/clusivity"
module ActiveModel
# == Active Model Inclusion Validator
module Validations
- class InclusionValidator < EachValidator
- ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " <<
- "and must be supplied as the :in option of the configuration hash"
-
- def check_validity!
- unless [:include?, :call].any?{ |method| options[:in].respond_to?(method) }
- raise ArgumentError, ERROR_MESSAGE
- end
- end
+ class InclusionValidator < EachValidator #:nodoc:
+ include Clusivity
def validate_each(record, attribute, value)
- delimiter = options[:in]
- exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter
- unless exclusions.send(inclusion_method(exclusions), value)
- record.errors.add(attribute, :inclusion, options.except(:in).merge!(:value => value))
+ unless include?(record, value)
+ record.errors.add(attribute, :inclusion, options.except(:in, :within).merge!(:value => value))
end
end
-
- private
-
- # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
- # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
- # uses the previous logic of comparing a value with the range endpoints.
- def inclusion_method(enumerable)
- enumerable.is_a?(Range) ? :cover? : :include?
- end
end
module HelperMethods
- # Validates whether the value of the specified attribute is available in a particular enumerable object.
+ # Validates whether the value of the specified attribute is available in a
+ # particular enumerable object.
#
# class Person < ActiveRecord::Base
- # validates_inclusion_of :gender, :in => %w( m f )
- # validates_inclusion_of :age, :in => 0..99
- # validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %{value} is not included in the list"
- # validates_inclusion_of :states, :in => lambda{ |person| STATES[person.country] }
+ # validates_inclusion_of :gender, in: %w( m f )
+ # validates_inclusion_of :age, in: 0..99
+ # validates_inclusion_of :format, in: %w( jpg gif png ), message: "extension %{value} is not included in the list"
+ # validates_inclusion_of :states, in: ->(person) { STATES[person.country] }
+ # validates_inclusion_of :karma, in: :available_karmas
# end
#
# Configuration options:
# * <tt>:in</tt> - An enumerable object of available items. This can be
- # supplied as a proc or lambda which returns an enumerable. If the enumerable
- # is a range the test is performed with <tt>Range#cover?</tt>
- # (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
- # and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # supplied as a proc, lambda or symbol which returns an enumerable. If the
+ # enumerable is a range the test is performed with <tt>Range#cover?</tt>,
+ # otherwise with <tt>include?</tt>.
+ # * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is
+ # not included in the list").
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the
+ # attribute is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
+ # attribute is blank (default is +false+).
+ #
+ # There is also a list of default options supported by every validator:
+ # +:if+, +:unless+, +:on+ and +:strict+.
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
def validates_inclusion_of(*attr_names)
validates_with InclusionValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 0bbd81a984..e4a1f9e80a 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -1,10 +1,8 @@
-require "active_support/core_ext/string/encoding"
-
module ActiveModel
# == Active Model Length Validator
module Validations
- class LengthValidator < EachValidator
+ class LengthValidator < EachValidator #:nodoc:
MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
@@ -29,7 +27,7 @@ module ActiveModel
keys.each do |key|
value = options[key]
- unless value.is_a?(Integer) && value >= 0 or value == Float::INFINITY
+ unless (value.is_a?(Integer) && value >= 0) || value == Float::INFINITY
raise ArgumentError, ":#{key} must be a nonnegative Integer or Infinity"
end
end
@@ -38,12 +36,12 @@ module ActiveModel
def validate_each(record, attribute, value)
value = tokenize(value)
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
-
+ errors_options = options.except(*RESERVED_OPTIONS)
+
CHECKS.each do |key, validity_check|
next unless check_value = options[key]
next if value_length.send(validity_check, check_value)
- errors_options = options.except(*RESERVED_OPTIONS)
errors_options[:count] = check_value
default_message = options[MESSAGES[key]]
@@ -64,45 +62,48 @@ module ActiveModel
module HelperMethods
- # Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time:
+ # Validates that the specified attribute matches the length restrictions
+ # supplied. Only one option can be used at a time:
#
# class Person < ActiveRecord::Base
- # validates_length_of :first_name, :maximum => 30
- # validates_length_of :last_name, :maximum => 30, :message => "less than 30 if you don't mind"
- # validates_length_of :fax, :in => 7..32, :allow_nil => true
- # validates_length_of :phone, :in => 7..32, :allow_blank => true
- # validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
- # validates_length_of :zip_code, :minimum => 5, :too_short => "please enter at least 5 characters"
- # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with 4 characters... don't play me."
- # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words.", :tokenizer => lambda { |str| str.scan(/\w+/) }
+ # validates_length_of :first_name, maximum: 30
+ # validates_length_of :last_name, maximum: 30, message: "less than 30 if you don't mind"
+ # validates_length_of :fax, in: 7..32, allow_nil: true
+ # validates_length_of :phone, in: 7..32, allow_blank: true
+ # validates_length_of :user_name, within: 6..20, too_long: 'pick a shorter name', too_short: 'pick a longer name'
+ # validates_length_of :zip_code, minimum: 5, too_short: 'please enter at least 5 characters'
+ # validates_length_of :smurf_leader, is: 4, message: "papa is spelled with 4 characters... don't play me."
+ # validates_length_of :essay, minimum: 100, too_short: 'Your essay must be at least 100 words.',
+ # tokenizer: ->(str) { str.scan(/\w+/) }
# end
#
# Configuration options:
# * <tt>:minimum</tt> - The minimum size of the attribute.
# * <tt>:maximum</tt> - The maximum size of the attribute.
# * <tt>:is</tt> - The exact size of the attribute.
- # * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
- # * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
+ # * <tt>:within</tt> - A range specifying the minimum and maximum size of
+ # the attribute.
+ # * <tt>:in</tt> - A synonym (or alias) for <tt>:within</tt>.
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
- # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %{count} characters)").
- # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %{count} characters)").
- # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %{count} characters)").
- # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
- # and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
- # count words as in above example.)
- # Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # * <tt>:too_long</tt> - The error message if the attribute goes over the
+ # maximum (default is: "is too long (maximum is %{count} characters)").
+ # * <tt>:too_short</tt> - The error message if the attribute goes under the
+ # minimum (default is: "is too short (min is %{count} characters)").
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt>
+ # method and the attribute is the wrong size (default is: "is the wrong
+ # length (should be %{count} characters)").
+ # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
+ # <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
+ # <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
+ # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
+ # (e.g. <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words
+ # as in above example). Defaults to <tt>->(value) { value.split(//) }</tt>
+ # which counts individual characters.
+ #
+ # There is also a list of default options supported by every validator:
+ # +:if+, +:unless+, +:on+ and +:strict+.
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
def validates_length_of(*attr_names)
validates_with LengthValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index bb9f9679fc..edebca94a8 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -2,7 +2,7 @@ module ActiveModel
# == Active Model Numericality Validator
module Validations
- class NumericalityValidator < EachValidator
+ class NumericalityValidator < EachValidator #:nodoc:
CHECKS = { :greater_than => :>, :greater_than_or_equal_to => :>=,
:equal_to => :==, :less_than => :<, :less_than_or_equal_to => :<=,
:odd => :odd?, :even => :even?, :other_than => :!= }.freeze
@@ -79,50 +79,56 @@ module ActiveModel
end
module HelperMethods
- # Validates whether the value of the specified attribute is numeric by trying to convert it to
- # a float with Kernel.Float (if <tt>only_integer</tt> is false) or applying it to the regular expression
- # <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>only_integer</tt> is set to true).
+ # Validates whether the value of the specified attribute is numeric by
+ # trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
+ # is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\Z/</tt>
+ # (if <tt>only_integer</tt> is set to +true+).
#
# class Person < ActiveRecord::Base
- # validates_numericality_of :value, :on => :create
+ # validates_numericality_of :value, on: :create
# end
#
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "is not a number").
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
- # and <tt>:update</tt>.
- # * <tt>:only_integer</tt> - Specifies whether the value has to be an integer, e.g. an integral value (default is +false+).
- # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is +false+). Notice that for fixnum and float columns empty strings are converted to +nil+.
- # * <tt>:greater_than</tt> - Specifies the value must be greater than the supplied value.
- # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater than or equal the supplied value.
- # * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied value.
- # * <tt>:less_than</tt> - Specifies the value must be less than the supplied value.
- # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or equal the supplied value.
- # * <tt>:other_than</tt> - Specifies the value must be other than the supplied value.
+ # * <tt>:only_integer</tt> - Specifies whether the value has to be an
+ # integer, e.g. an integral value (default is +false+).
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
+ # +false+). Notice that for fixnum and float columns empty strings are
+ # converted to +nil+.
+ # * <tt>:greater_than</tt> - Specifies the value must be greater than the
+ # supplied value.
+ # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be
+ # greater than or equal the supplied value.
+ # * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied
+ # value.
+ # * <tt>:less_than</tt> - Specifies the value must be less than the
+ # supplied value.
+ # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less
+ # than or equal the supplied value.
+ # * <tt>:other_than</tt> - Specifies the value must be other than the
+ # supplied value.
# * <tt>:odd</tt> - Specifies the value must be an odd number.
# * <tt>:even</tt> - Specifies the value must be an even number.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
#
- # The following checks can also be supplied with a proc or a symbol which corresponds to a method:
+ # There is also a list of default options supported by every validator:
+ # +:if+, +:unless+, +:on+ and +:strict+ .
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
+ #
+ # The following checks can also be supplied with a proc or a symbol which
+ # corresponds to a method:
+ #
# * <tt>:greater_than</tt>
# * <tt>:greater_than_or_equal_to</tt>
# * <tt>:equal_to</tt>
# * <tt>:less_than</tt>
# * <tt>:less_than_or_equal_to</tt>
#
+ # For example:
+ #
# class Person < ActiveRecord::Base
- # validates_numericality_of :width, :less_than => Proc.new { |person| person.height }
- # validates_numericality_of :width, :greater_than => :minimum_weight
+ # validates_numericality_of :width, less_than: Proc.new { |person| person.height }
+ # validates_numericality_of :width, greater_than: :minimum_weight
# end
- #
def validates_numericality_of(*attr_names)
validates_with NumericalityValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb
index 9a643a6f5c..f159e40858 100644
--- a/activemodel/lib/active_model/validations/presence.rb
+++ b/activemodel/lib/active_model/validations/presence.rb
@@ -1,17 +1,17 @@
-require 'active_support/core_ext/object/blank'
module ActiveModel
# == Active Model Presence Validator
module Validations
- class PresenceValidator < EachValidator
+ class PresenceValidator < EachValidator #:nodoc:
def validate(record)
record.errors.add_on_blank(attributes, options)
end
end
module HelperMethods
- # Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example:
+ # Validates that the specified attributes are not blank (as defined by
+ # Object#blank?). Happens by default on save.
#
# class Person < ActiveRecord::Base
# validates_presence_of :first_name
@@ -19,25 +19,19 @@ module ActiveModel
#
# The first_name attribute must be in the object and it cannot be blank.
#
- # If you want to validate the presence of a boolean field (where the real values are true and false),
- # you will want to use <tt>validates_inclusion_of :field_name, :in => [true, false]</tt>.
+ # If you want to validate the presence of a boolean field (where the real
+ # values are +true+ and +false+), you will want to use
+ # <tt>validates_inclusion_of :field_name, in: [true, false]</tt>.
#
- # This is due to the way Object#blank? handles boolean values: <tt>false.blank? # => true</tt>.
+ # This is due to the way Object#blank? handles boolean values:
+ # <tt>false.blank? # => true</tt>.
#
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "can't be blank").
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
- # and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or false value.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
#
+ # There is also a list of default options supported by every validator:
+ # +:if+, +:unless+, +:on+ and +:strict+.
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
def validates_presence_of(*attr_names)
validates_with PresenceValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index d94c4e3f4f..eb6e604851 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -11,18 +11,18 @@ module ActiveModel
#
# 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
+ # 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.
+ # and default validators in one call for a given attribute.
#
# class EmailValidator < ActiveModel::EachValidator
# def validate_each(record, attribute, value)
@@ -35,12 +35,12 @@ module ActiveModel
# include ActiveModel::Validations
# attr_accessor :name, :email
#
- # validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 }
- # validates :email, :presence => true, :email => true
+ # 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.
+ # allowing custom modules of validators to be included as needed.
#
# class Film
# include ActiveModel::Validations
@@ -51,33 +51,53 @@ module ActiveModel
# end
# end
#
- # validates :name, :title => true
+ # validates :name, title: true
# end
#
- # Additionally validator classes may be in another namespace and still used within any class.
+ # 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, e.g.
+ # 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
+ # 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]+
+ # validator's initializer as <tt>options[:in]</tt> while other types
+ # including regular expressions and strings are passed as <tt>options[:with]</tt>.
#
- # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+ and +:strict+
- # can be given to one specific validator, as a hash:
+ # There is also a list of options that could be used along with validators:
#
- # validates :password, :presence => { :if => :password_required? }, :confirmation => true
+ # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
+ # validation contexts by default (+nil+), other options are <tt>:create</tt>
+ # and <tt>:update</tt>.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
+ # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
+ # proc or string should return or evaluate to a +true+ or +false+ value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
+ # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # method, proc or string should return or evaluate to a +true+ or
+ # +false+ value.
+ # * <tt>:strict</tt> - if the <tt>:strict</tt> option is set to true
+ # will raise ActiveModel::StrictValidationFailed instead of adding the error.
+ # <tt>:strict</tt> option can also be set to any other exception.
#
- # Or to all at the same time:
+ # Example:
#
- # validates :password, :presence => true, :confirmation => true, :if => :password_required?
+ # 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+
+ # and +:strict+ can be given to one specific validator, as a hash:
+ #
+ # validates :password, presence: { if: :password_required? }, confirmation: true
def validates(*attributes)
defaults = attributes.extract_options!.dup
validations = defaults.slice!(*_validates_default_keys)
@@ -88,6 +108,7 @@ module ActiveModel
defaults.merge!(:attributes => attributes)
validations.each do |key, options|
+ next unless options
key = "#{key.to_s.camelize}Validator"
begin
@@ -104,8 +125,20 @@ module ActiveModel
# users and are considered exceptional. So each validator defined with bang
# or <tt>:strict</tt> option set to <tt>true</tt> will always raise
# <tt>ActiveModel::StrictValidationFailed</tt> instead of adding error
- # when validation fails.
- # See <tt>validates</tt> for more information about the validation itself.
+ # when validation fails. See <tt>validates</tt> 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
def validates!(*attributes)
options = attributes.extract_options!
options[:strict] = true
@@ -116,7 +149,7 @@ module ActiveModel
# When creating custom validators, it might be useful to be able to specify
# additional default keys. This can be done by overwriting this method.
- def _validates_default_keys
+ def _validates_default_keys #:nodoc:
[:if, :unless, :on, :allow_blank, :allow_nil , :strict]
end
diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb
index 72b8562b93..869591cd9e 100644
--- a/activemodel/lib/active_model/validations/with.rb
+++ b/activemodel/lib/active_model/validations/with.rb
@@ -3,12 +3,14 @@ module ActiveModel
module HelperMethods
private
def _merge_attributes(attr_names)
- options = attr_names.extract_options!
- options.merge(:attributes => attr_names.flatten)
+ options = attr_names.extract_options!.symbolize_keys
+ attr_names.flatten!
+ options[:attributes] = attr_names
+ options
end
end
- class WithValidator < EachValidator
+ class WithValidator < EachValidator #:nodoc:
def validate_each(record, attr, val)
method_name = options[:with]
@@ -32,7 +34,7 @@ module ActiveModel
# class MyValidator < ActiveModel::Validator
# def validate(record)
# if some_complex_logic
- # record.errors.add :base, "This record is invalid"
+ # record.errors.add :base, 'This record is invalid'
# end
# end
#
@@ -46,30 +48,32 @@ module ActiveModel
#
# class Person
# include ActiveModel::Validations
- # validates_with MyValidator, MyOtherValidator, :on => :create
+ # validates_with MyValidator, MyOtherValidator, on: :create
# end
#
# Configuration options:
# * <tt>:on</tt> - Specifies when this validation is active
- # (<tt>:create</tt> or <tt>:update</tt>
+ # (<tt>:create</tt> or <tt>:update</tt>.
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
- # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
- # or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or false value.
+ # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
+ # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>).
+ # The method, proc or string should return or evaluate to a +true+ or
+ # +false+ value.
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
# determine if the validation should not occur
- # (e.g. <tt>:unless => :skip_validation</tt>, or
- # <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or false value.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
-
+ # (e.g. <tt>unless: :skip_validation</tt>, or
+ # <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>).
+ # The method, proc or string should return or evaluate to a +true+ or
+ # +false+ value.
+ # * <tt>:strict</tt> - Specifies whether validation should be strict.
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
+ #
# If you pass any additional configuration options, they will be passed
- # to the class and available as <tt>options</tt>:
+ # to the class and available as +options+:
#
# class Person
# include ActiveModel::Validations
- # validates_with MyValidator, :my_custom_key => "my custom value"
+ # validates_with MyValidator, my_custom_key: 'my custom value'
# end
#
# class MyValidator < ActiveModel::Validator
@@ -77,7 +81,6 @@ module ActiveModel
# options[:my_custom_key] # => "my custom value"
# end
# end
- #
def validates_with(*args, &block)
options = args.extract_options!
args.each do |klass|
@@ -118,22 +121,21 @@ module ActiveModel
# class Person
# include ActiveModel::Validations
#
- # validate :instance_validations, :on => :create
+ # validate :instance_validations, on: :create
#
# def instance_validations
# validates_with MyValidator, MyOtherValidator
# end
# end
#
- # Standard configuration options (:on, :if and :unless), which are
- # available on the class version of validates_with, should instead be
- # placed on the <tt>validates</tt> method as these are applied and tested
- # in the callback
+ # Standard configuration options (<tt>:on</tt>, <tt>:if</tt> and
+ # <tt>:unless</tt>), which are available on the class version of
+ # +validates_with+, should instead be placed on the +validates+ method
+ # as these are applied and tested in the callback.
#
# If you pass any additional configuration options, they will be passed
- # to the class and available as <tt>options</tt>, please refer to the
- # class version of this method for more information
- #
+ # to the class and available as +options+, please refer to the
+ # class version of this method for more information.
def validates_with(*args, &block)
options = args.extract_options!
args.each do |klass|