原创作者: hideto
阅读:1608次
评论:0条
更新时间:2011-05-26
Callbacks相关的源码在callbacks.rb文件里:
从源码中我们可以学习如下几点:
1,有四种类型的callback macros:
1)Method references(symbol)
2)Callback objects
3)Inline methods(proc)
4)Inline eval methods(string)
2,执行Model的如下方法时会调用callbacks:
instantiate(find)、initialize、create_or_update、valid?、create、update、destroy
3,activesupport\lib\activesupport\core_text\module\aliasing.rb:
比如alias_method_chain :destroy, :callbacks的效果是调用destroy方法时会调用destroy_with_callbacks
而destroy_with_callbacks方法先调用callback(:before_destroy),然后destroy_without_callbacks(又被alias为destroy),然后callback(:after_destroy)
然后callback(:before_destroy)和callback(:after_destroy)分别调用before_destroy和after_destroy后面的macros
ActiveRecord的Callback就像一个Around_filter,实现了aop拦截的功能
module ActiveRecord module Callbacks CALLBACKS = %w( after_find after_initialize before_save after_save before_create after_create before_update after_update before_validation after_validation before_validation_on_create after_validation_on_create before_validation_on_update after_validation_on_update before_destroy after_destroy ) def self.included(base) #:nodoc: base.extend(ClassMethods) base.class_eval do class << self include Observable alias_method_chain :instantiate, :callbacks end [:initialize, :create_or_update, :valid?, :create, :update, :destroy].each do |method| alias_method_chain method, :callbacks end 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 end module ClassMethods #:nodoc: def instantiate_with_callbacks(record) object = instantiate_without_callbacks(record) if object.respond_to_without_attributes?(:after_find) object.send(:callback, :after_find) end if object.respond_to_without_attributes?(:after_initialize) object.send(:callback, :after_initialize) end object end end def create_or_update_with_callbacks #:nodoc: return false if callback(:before_save) == false result = create_or_update_without_callbacks callback(:after_save) result end def create_with_callbacks #:nodoc: return false if callback(:before_create) == false result = create_without_callbacks callback(:after_create) result end def update_with_callbacks #:nodoc: return false if callback(:before_update) == false result = update_without_callbacks callback(:after_update) result end def valid_with_callbacks? #:nodoc: return false if callback(:before_validation) == false if new_record? then result = callback(:before_validation_on_create) else result = callback(:before_validation_on_update) end return false if result == false result = valid_without_callbacks? callback(:after_validation) if new_record? then callback(:after_validation_on_create) else callback(:after_validation_on_update) end return result end def destroy_with_callbacks #:nodoc: return false if callback(:before_destroy) == false result = destroy_without_callbacks callback(:after_destroy) result end private 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 = send(method) if respond_to_without_attributes?(method) return result end def callbacks_for(method) self.class.read_inheritable_attribute(method.to_sym) or [] end end end
从源码中我们可以学习如下几点:
1,有四种类型的callback macros:
1)Method references(symbol)
class Topic < ActiveRecord::Base before_destroy :destroy_author end
2)Callback objects
class BankAccount < ActiveRecord::Base before_save EncryptionWrapper.new("credit_card_number") after_save EncryptionWrapper.new("credit_card_number") after_initialize EncryptionWrapper.new("credit_card_number") end class EncryptionWrapper def initialize(attribute) @attribute = attribute end def before_save(record) record.credit_card_number = encrypt(record.credit_card_number) end def after_save(record) record.credit_card_number = decrypt(record.credit_card_number) end alias_method :after_find, :after_save private def encrypt(value) # Secrecy is committed end def decrypt(value) # Secrecy is unveiled end end
3)Inline methods(proc)
class Firm < ActiveRecord::Base # Destroys the associated clients and people when the firm is destroyed before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" } before_destroy { |record| Client.destroy_all "client_of = #{record.id}" } end
4)Inline eval methods(string)
class Topic < ActiveRecord::Base before_destroy 'self.class.delete_all "parent_id = #{id}"' end
2,执行Model的如下方法时会调用callbacks:
instantiate(find)、initialize、create_or_update、valid?、create、update、destroy
3,activesupport\lib\activesupport\core_text\module\aliasing.rb:
class Module def alias_method_chain(target, feature) aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 yield(aliased_target, punctuation) if block_given? alias_method "#{aliased_target}_without_#{feature}#{punctuation}", target alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}" end end
比如alias_method_chain :destroy, :callbacks的效果是调用destroy方法时会调用destroy_with_callbacks
而destroy_with_callbacks方法先调用callback(:before_destroy),然后destroy_without_callbacks(又被alias为destroy),然后callback(:after_destroy)
然后callback(:before_destroy)和callback(:after_destroy)分别调用before_destroy和after_destroy后面的macros
ActiveRecord的Callback就像一个Around_filter,实现了aop拦截的功能
评论 共 0 条 请登录后发表评论