diff options
author | José Valim <jose.valim@gmail.com> | 2009-12-23 01:37:19 +0100 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2009-12-23 01:38:15 +0100 |
commit | 279067639f319f3b4bbcaf90c26f286e96df2c77 (patch) | |
tree | 84ea6824ddc154c526d6d1094f20904cc5a25c81 /activemodel/lib | |
parent | 977a5c43b160d8aa8d1b87bb0feb54db85fe203c (diff) | |
download | rails-279067639f319f3b4bbcaf90c26f286e96df2c77.tar.gz rails-279067639f319f3b4bbcaf90c26f286e96df2c77.tar.bz2 rails-279067639f319f3b4bbcaf90c26f286e96df2c77.zip |
validates_each uses a BlockValidator.
Diffstat (limited to 'activemodel/lib')
-rw-r--r-- | activemodel/lib/active_model.rb | 1 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations.rb | 56 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/length.rb | 7 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/with.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/validator.rb | 22 |
5 files changed, 49 insertions, 41 deletions
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index 6aa80da23f..abb04cd624 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -46,6 +46,7 @@ module ActiveModel autoload :ValidationsRepairHelper autoload :Validator autoload :EachValidator, 'active_model/validator' + autoload :BlockValidator, 'active_model/validator' autoload :VERSION module Serializers diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 064ec98f3a..f1a15ec1d8 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -12,6 +12,29 @@ module ActiveModel end module ClassMethods + # Validates each attribute against a block. + # + # class Person < ActiveRecord::Base + # validates_each :first_name, :last_name do |record, attr, value| + # record.errors.add attr, 'starts with z.' if value[0] == ?z + # end + # end + # + # Options: + # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). + # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+. + # * <tt>:allow_blank</tt> - Skip validation if attribute is blank. + # * <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. + def validates_each(*attr_names, &block) + options = attr_names.extract_options!.symbolize_keys + validates_with BlockValidator, options.merge(:attributes => attr_names.flatten), &block + end + # Adds a validation method or block to the class. This is useful when # overriding the +validate+ instance method becomes too unwieldly and # you're looking for more descriptive declaration of your validations. @@ -39,39 +62,6 @@ module ActiveModel # end # # This usage applies to +validate_on_create+ and +validate_on_update as well+. - - # Validates each attribute against a block. - # - # class Person < ActiveRecord::Base - # validates_each :first_name, :last_name do |record, attr, value| - # record.errors.add attr, 'starts with z.' if value[0] == ?z - # end - # end - # - # Options: - # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). - # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+. - # * <tt>:allow_blank</tt> - Skip validation if attribute is blank. - # * <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. - def validates_each(*attrs) - options = attrs.extract_options!.symbolize_keys - attrs = attrs.flatten - - # Declare the validation. - validate options do |record| - attrs.each do |attr| - value = record.send(:read_attribute_for_validation, attr) - next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank]) - yield record, attr, value - end - end - end - def validate(*args, &block) options = args.last if options.is_a?(Hash) && options.key?(:on) diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 1214c5f4bf..04280b401b 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -10,8 +10,8 @@ module ActiveModel def initialize(options) options[:tokenizer] ||= DEFAULT_TOKENIZER - super @type = (OPTIONS & options.keys).first + super end def check_validity! @@ -108,9 +108,8 @@ module ActiveModel # count words as in above example.) # Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters. def validates_length_of(*attr_names) - options = { :tokenizer => DEFAULT_TOKENIZER } - options.update(attr_names.extract_options!) - validates_with LengthValidator, options.merge(:attributes => attr_names, :type => type) + options = attr_names.extract_options! + validates_with LengthValidator, options.merge(:attributes => attr_names) end alias_method :validates_size_of, :validates_length_of diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb index 626e9d5731..8d521173c6 100644 --- a/activemodel/lib/active_model/validations/with.rb +++ b/activemodel/lib/active_model/validations/with.rb @@ -48,9 +48,9 @@ module ActiveModel # end # end # - def validates_with(*args) + def validates_with(*args, &block) options = args.extract_options! - args.each { |klass| validate(klass.new(options), options) } + args.each { |klass| validate(klass.new(options, &block), options) } end end end diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb index 342c4691ff..8c9f9c7fb3 100644 --- a/activemodel/lib/active_model/validator.rb +++ b/activemodel/lib/active_model/validator.rb @@ -51,7 +51,6 @@ module ActiveModel #:nodoc: # @my_custom_field = options[:field_name] || :first_name # end # end - # class Validator attr_reader :options @@ -64,6 +63,11 @@ module ActiveModel #:nodoc: end end + # EachValidator is a validator which iterates through the attributes given + # in the options hash invoking the validate_each method passing in the + # record, attribute and value. + # + # All ActiveModel validations are built on top of this Validator. class EachValidator < Validator attr_reader :attributes @@ -81,11 +85,25 @@ module ActiveModel #:nodoc: end end - def validate_each(record) + def validate_each(record, attribute, value) raise NotImplementedError end def check_validity! end end + + # BlockValidator is a special EachValidator which receives a block on initialization + # and call this block for each attribute being validated. +validates_each+ uses this + # Validator. + class BlockValidator < EachValidator + def initialize(options, &block) + @block = block + super + end + + def validate_each(record, attribute, value) + @block.call(record, attribute, value) + end + end end |