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。在這種情況下,將呼叫所有型別的回撥。"
=