跳转到内容

Ruby on Rails/ActiveRecord/回调

来自维基教科书,开放书籍,开放世界

回调提供了一种方法来挂钩到 ActiveRecord 对象的生命周期。

实现回调

[编辑 | 编辑源代码]

回调宏接受四种类型的回调

  • 方法引用(符号)
  • 回调对象
  • 内联方法(使用 proc)
  • 内联 eval 方法(使用字符串) - 已弃用。

方法引用和回调对象是推荐的方法,使用 proc 的内联方法有时是合适的(例如,用于创建 mix-in),而内联 eval 方法已被弃用。

方法引用

[编辑 | 编辑源代码]

方法引用回调通过指定对象中可用的受保护或私有方法来工作,例如

  class Topic < ActiveRecord::Base
    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

因此,您指定您希望在给定回调上进行消息传递的对象。当该回调被触发时,该对象将有一个与回调名称相同的方法进行消息传递。

使用 Proc 进行回调的示例

  class Person
    before_save Proc.new { |model| model.do_something }
  end

内联Eval

[编辑 | 编辑源代码]

回调宏通常接受一个表示他们应该运行的方法的符号,但您也可以传递一个“方法字符串”,该字符串将在回调的绑定中进行评估。例如

  class Topic < ActiveRecord::Base
    before_destroy 'self.class.delete_all "parent_id = #{id}"'
  end

注意,使用单引号 (’) 这样 #{id} 部分直到回调被触发才被评估。还要注意,这些内联回调可以像普通回调一样叠加

  class Topic < ActiveRecord::Base
    before_destroy 'self.class.delete_all "parent_id = #{id}"',
                   'puts "Evaluated after parents are destroyed"'
  end

回调参考

[编辑 | 编辑源代码]

before_save

[编辑 | 编辑源代码]

此方法在保存 ActiveRecord 对象之前被调用。

after_save

[编辑 | 编辑源代码]

一旦 active record 对象保存,某些方法将在该场景中被触发,我们需要使用 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

[编辑 | 编辑源代码]

部分文档化的回调

[编辑 | 编辑源代码]

以下回调是部分文档化的。由于 [1] 性能问题,不鼓励使用它们。

after_find

[编辑 | 编辑源代码]

只有当模型类中存在明确的实现时,才会执行 after_find 回调。它将针对 find 返回的每个对象调用,因此可能会影响性能,如 [1] Rails API 文档中所述。

after_initialize

[编辑 | 编辑源代码]

只有当模型类中存在明确的实现时,才会执行 after_initialize 方法。它将在每次初始化 ActiveRecord 模型时调用。它将针对 find 返回的每个对象调用,因此可能会影响性能,如 [1] Rails API 文档中所述。

参考文献

[编辑 | 编辑源代码]
  1. a b c "由于 after_find 和 after_initialize 会针对每个由查找器找到和实例化的对象调用,例如 Base.find(:all),因此我们必须实施一个简单的性能限制(在一个简单的测试用例中速度提高了 50%)。与所有其他回调不同,只有在定义了明确的实现时(def after_find),才会运行 after_find 和 after_initialize。在这种情况下,将调用所有类型的回调。"

=

华夏公益教科书