diff options
Diffstat (limited to 'activemodel/lib/active_model/validations')
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| |