diff options
Diffstat (limited to 'activerecord')
-rwxr-xr-x | activerecord/lib/active_record/callbacks.rb | 41 | ||||
-rwxr-xr-x | activerecord/lib/active_record/validations.rb | 122 | ||||
-rwxr-xr-x | activerecord/test/cases/validations_test.rb | 2 |
3 files changed, 38 insertions, 127 deletions
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 9a9bf28323..67a4117d20 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -183,14 +183,8 @@ module ActiveRecord base.send :alias_method_chain, method, :callbacks end - CALLBACKS.each do |method| - base.class_eval <<-"end_eval" - def self.#{method}(*callbacks, &block) - callbacks << block if block_given? - write_inheritable_array(#{method.to_sym.inspect}, callbacks) - end - end_eval - end + base.send :include, ActiveSupport::Callbacks + base.define_callbacks *CALLBACKS end # Is called when the object was instantiated by one of the finders, like <tt>Base.find</tt>. @@ -301,38 +295,15 @@ module ActiveRecord def callback(method) notify(method) - callbacks_for(method).each do |callback| - result = case callback - when Symbol - self.send(callback) - when String - eval(callback, binding) - when Proc, Method - callback.call(self) - else - if callback.respond_to?(method) - callback.send(method, self) - else - raise ActiveRecordError, "Callbacks must be a symbol denoting the method to call, a string to be evaluated, a block to be invoked, or an object responding to the callback method." - end - end - return false if result == false - end + result = run_callbacks(method) { |result, object| result == false } - result = send(method) if respond_to_without_attributes?(method) + if result != false && respond_to_without_attributes?(method) + result = send(method) + end return result end - def callbacks_for(method) - self.class.read_inheritable_attribute(method.to_sym) or [] - end - - def invoke_and_notify(method) - notify(method) - send(method) if respond_to_without_attributes?(method) - end - def notify(method) #:nodoc: self.class.changed self.class.notify_observers(method, self) diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 98dfcece8b..87f128e9a3 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -279,6 +279,25 @@ module ActiveRecord alias_method_chain :save!, :validation alias_method_chain :update_attribute, :validation_skipping end + + base.send :include, ActiveSupport::Callbacks + + # TODO: Use helper ActiveSupport::Callbacks#define_callbacks instead + %w( validate validate_on_create validate_on_update ).each do |validation_method| + base.class_eval <<-"end_eval" + def self.#{validation_method}(*methods, &block) + options = methods.extract_options! + methods << block if block_given? + methods.map! { |method| Callback.new(:#{validation_method}, method, options) } + existing_methods = read_inheritable_attribute(:#{validation_method}) || [] + write_inheritable_attribute(:#{validation_method}, existing_methods | methods) + end + + def self.#{validation_method}_callback_chain + read_inheritable_attribute(:#{validation_method}) || [] + end + end_eval + end end # All of the following validations are defined in the class scope of the model that you're interested in validating. @@ -324,43 +343,6 @@ module ActiveRecord # end # # This usage applies to #validate_on_create and #validate_on_update as well. - def validate(*methods, &block) - methods << block if block_given? - write_inheritable_set(:validate, methods) - end - - def validate_on_create(*methods, &block) - methods << block if block_given? - write_inheritable_set(:validate_on_create, methods) - end - - def validate_on_update(*methods, &block) - methods << block if block_given? - write_inheritable_set(:validate_on_update, methods) - end - - def condition_block?(condition) - condition.respond_to?("call") && (condition.arity == 1 || condition.arity == -1) - end - - # Determine from the given condition (whether a block, procedure, method or string) - # whether or not to validate the record. See #validates_each. - def evaluate_condition(condition, record) - case condition - when Symbol; record.send(condition) - when String; eval(condition, record.instance_eval { binding }) - else - if condition_block?(condition) - condition.call(record) - else - raise( - ActiveRecordError, - "Validations need to be either a symbol, string (to be eval'ed), proc/method, or " + - "class implementing a static validation method" - ) - end - end - end # Validates each attribute against a block. # @@ -379,20 +361,17 @@ module ActiveRecord # 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. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The - # method, proc or string should return or evaluate to a true or false value. + # 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. - send(validation_method(options[:on] || :save)) do |record| - # Don't validate when there is an :if condition and that condition is false or there is an :unless condition and that condition is true - unless (options[:if] && !evaluate_condition(options[:if], record)) || (options[:unless] && evaluate_condition(options[:unless], record)) - attrs.each do |attr| - value = record.send(attr) - next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank]) - yield record, attr, value - end + send(validation_method(options[:on] || :save), options) do |record| + attrs.each do |attr| + value = record.send(attr) + next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank]) + yield record, attr, value end end end @@ -515,11 +494,9 @@ module ActiveRecord # can't use validates_each here, because it cannot cope with nonexistent attributes, # while errors.add_on_empty can - send(validation_method(configuration[:on])) do |record| - unless (configuration[:if] && !evaluate_condition(configuration[:if], record)) || (configuration[:unless] && evaluate_condition(configuration[:unless], record)) - record.errors.add_on_blank(attr_names, configuration[:message]) - end - end + send(validation_method(configuration[:on]), configuration) do |record| + record.errors.add_on_blank(attr_names, configuration[:message]) + end end # Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time: @@ -911,13 +888,7 @@ module ActiveRecord end end - private - def write_inheritable_set(key, methods) - existing_methods = read_inheritable_attribute(key) || [] - write_inheritable_attribute(key, existing_methods | methods) - end - def validation_method(on) case on when :save then :validate @@ -959,14 +930,14 @@ module ActiveRecord def valid? errors.clear - run_validations(:validate) + run_callbacks(:validate) validate if new_record? - run_validations(:validate_on_create) + run_callbacks(:validate_on_create) validate_on_create else - run_validations(:validate_on_update) + run_callbacks(:validate_on_update) validate_on_update end @@ -990,36 +961,5 @@ module ActiveRecord # Overwrite this method for validation checks used only on updates. def validate_on_update # :doc: end - - private - def run_validations(validation_method) - validations = self.class.read_inheritable_attribute(validation_method.to_sym) - if validations.nil? then return end - validations.each do |validation| - if validation.is_a?(Symbol) - self.send(validation) - elsif validation.is_a?(String) - eval(validation, binding) - elsif validation_block?(validation) - validation.call(self) - elsif validation_class?(validation, validation_method) - validation.send(validation_method, self) - else - raise( - ActiveRecordError, - "Validations need to be either a symbol, string (to be eval'ed), proc/method, or " + - "class implementing a static validation method" - ) - end - end - end - - def validation_block?(validation) - validation.respond_to?("call") && (validation.arity == 1 || validation.arity == -1) - end - - def validation_class?(validation, validation_method) - validation.respond_to?(validation_method) - end end end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index e48844ece7..07936a783d 100755 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -1017,7 +1017,7 @@ class ValidationsTest < ActiveSupport::TestCase def test_invalid_validator Topic.validate 3 - assert_raise(ActiveRecord::ActiveRecordError) { t = Topic.create } + assert_raise(ArgumentError) { t = Topic.create } end def test_throw_away_typing |