`

Rails回调的示例

阅读更多
先补充一个部分的代码用来说明这些回调在一些实际中的用法,

class Profile < ActiveRecord::Base
  before_validation :archive#在验证之前判断,
  #为什么验证之前呢,因为如果是新建的话就不要验证了
  before_destroy :destroy_validate#删除的时候验证
  def archive
    return unless self.new_record?
    profile = Profile.find_by_name(self.name)
    unless profile.nil?
      profile.name = sprintf("a-%s", profile.id)
      profile.status = true
      unless profile.save 
        return false
      end
    end
  end
  def validate#修改默认的验证
    errors.add(:major_offset, "must be >= Minor Offset") unless major_offset >= minor_offset
    errors.add(:minor_offset, "must be <= Major Offset") unless minor_offset <= major_offset
     if Analyzer.count(:conditions => ["profile_id = ? and status= ?", self.id, Analyzer::INGRESS]) > 0
      errors.add_to_base("One or more Analyzers are in Ingress Monitoring mode and use this profile.  Edits are disabled until you stop Ingress Monitoring.")
      return false
    end
  end
  def destroy_validate#对应删除验证的描述
    if Analyzer.count(:conditions => ["profile_id = ? ", self.id]) > 0
      errors.add_to_base("One or more Analyzers use this profile, Delete are disabled.")
      return false
    end
	if SwitchPort.exists?(:profile_id=> self.id)
	  errors.add_to_base("One or more Analyzers use this profile, Delete are disabled.")
      return false
	end
  end
end


另这里有个Ruby On Rails验证大全你可能会关心


在看详细回调

通常在一个active record对象的生命周期里,有八个过程
引用
(-) save
(-) valid?
(1) before_validation
(2) before_validation_on_create
(-) validate
(-) validate_on_create
(3) after_validation
(4) after_validation_on_create
(5) before_save
(6) before_create
(-) create
(7) after_create
(8) after_save

这些stat是可以用来hook
下面是一个

回调的典型例子

  class CreditCard < ActiveRecord::Base
    # 这个例子用来说明预先处理信用卡数据,作用是在验证
    # 以前把输入的数据中不是数字的输入,屏蔽掉。就是把 "555 234 34"或者
    # "5552-3434" 都转换成 "55523434"
    def before_validation_on_create
      self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
    end
  end

 
  class Subscription < ActiveRecord::Base
    #这是另一个回调的例子,是在创建的时候,积累时间。
    #当然,这里是示例,没有人需要这个功能
    before_create :record_signup

    private
      def record_signup
        self.signed_up_on = Date.today
      end
  end

  class Firm < ActiveRecord::Base
    # 下面的例子也经常用就是相关删除。很多时候,这件事应该是dependent => :destroy
    # 来完成,当然,还有些时候比较复杂的回调,就会用到类似的方法
    # 当firm公司删除时,同时删除对应员工(Person)和客户(Client)
    before_destroy { |record| Person.destroy_all "firm_id = #{record.id}"   }
    before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
  end


有继承关系的回调

下面的情景是说,当在一个类中定义了回调。但,他有一个子类,又定义了一个回调。
  然后,我们希望,
        有些时候,回调继承执行。就是又要执行父类的回调,又要执行子类的回调。
        有些时候,希望子类的回调,重写覆盖父类的回调。
  那么,看看如何实现 
#这样的话,将实现回调的继承和队列调用
  class Topic < ActiveRecord::Base
    before_destroy :destroy_author
  end

  class Reply < Topic
    before_destroy :destroy_readers
  end
#也就是说,当Topic#destroy调用的时候 destroy_author将被执行。而,当Topic#destroy被执行的时候destroy_author和 destroy_readers将都被调用
#-------------------------------------------------------------------------
#下面的方法,将导致覆盖
class Topic < ActiveRecord::Base
    def before_destroy() destroy_author end
  end

  class Reply < Topic
    def before_destroy() destroy_readers end
  end
#这个时候,当Reply#destroy被调用时候将只调用destroy_readers将不会调用 destroy_author.
#-------------------------------------------------------------------------


回调的四种类型

  • Method references (符号),
  • callback objects(最常用吧),
  • inline methods (使用块方法),
  • and inline eval methods (字符串).

在这其中,前两种是推荐的回调表达方式。块方法的回调有些时候,也比较合适。最后的一种,基本废弃。

  class Topic < ActiveRecord::Base
    #这是标准的使用,把回调的方法本身,限制为private或者protected 
    before_destroy :delete_parents

    private
      def delete_parents
        self.class.delete_all "parent_id = #{id}"
      end
  end


回调的参数

回调方法的参数,是记录,根据传入的不同,灵活调用。
  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

method missing的应用

回调的宏,默认下会等待一个符号,但当我们在符号部分,使用method missing时,就可以在预期估值的时候,执行绑定的回调。

  class Topic < ActiveRecord::Base
    #实现act as tree的级联删除
    before_destroy 'self.class.delete_all "parent_id = #{id}"'
  end
  class Topic < ActiveRecord::Base
    before_destroy 'self.class.delete_all "parent_id = #{id}"',
                   'puts "Evaluated after parents are destroyed"'
  end



  •     *  after_create
  •     * after_destroy
  •     * after_save
  •     * after_update
  •     * after_validation
  •     * after_validation_on_create
  •     * after_validation_on_update
  •     * before_create
  •     * before_destroy
  •     * before_save
  •     * before_update
  •     * before_validation
  •     * before_validation_on_create
  •     * before_validation_on_update


http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
2
0
分享到:
评论
4 楼 Hooopo 2009-08-20  
good!
3 楼 夜鸣猪 2009-06-17  
wxmfly 写道

good&nbsp;

感谢光临,动力啊,
补充完了剩下部分的翻译
2 楼 wxmfly 2009-06-17  
good 
1 楼 xu_ch 2009-06-15  

相关推荐

Global site tag (gtag.js) - Google Analytics