跳轉到內容

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

=

華夏公益教科書