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
回调宏通常接受一个表示他们应该运行的方法的符号,但您也可以传递一个“方法字符串”,该字符串将在回调的绑定中进行评估。例如
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
此方法在保存 ActiveRecord 对象之前被调用。
一旦 active record 对象保存,某些方法将在该场景中被触发,我们需要使用 after_save 回调。
在创建模型的新对象之前被调用
在创建新对象并保存记录之前被调用
以下回调是部分文档化的。由于 [1] 性能问题,不鼓励使用它们。
只有当模型类中存在明确的实现时,才会执行 after_find 回调。它将针对 find 返回的每个对象调用,因此可能会影响性能,如 [1] Rails API 文档中所述。
只有当模型类中存在明确的实现时,才会执行 after_initialize 方法。它将在每次初始化 ActiveRecord 模型时调用。它将针对 find 返回的每个对象调用,因此可能会影响性能,如 [1] Rails API 文档中所述。
- ↑ a b c "由于 after_find 和 after_initialize 会针对每个由查找器找到和实例化的对象调用,例如 Base.find(:all),因此我们必须实施一个简单的性能限制(在一个简单的测试用例中速度提高了 50%)。与所有其他回调不同,只有在定义了明确的实现时(def after_find),才会运行 after_find 和 after_initialize。在这种情况下,将调用所有类型的回调。"
=