When would you use a before_save vs. after_save callback?
before_save 與 after_save 使用時機有何不同?
昨天簡介了callback這個有點容易混淆的名詞,簡單複習一下callback的概念,callback是在物件生命週期的特定時機執行某些程式碼,例如在物件創造前(before_create)、存取後(after_save),刪掉之後(after_destroy)等等。
## Create an object
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit/after_rollback
## Updating an Object
before_validation
after_validation
before_save
around_save
before_update
around_update
after_update
after_save
after_commit/after_rollback
如果需要在存取之後更新一個物件會需要額外的資料庫執行,所以如果需要更新物件的屬性(attribute),使用before_save
會是比較有效率的選擇,另外官方也提到盡量避免去在callback中去更新屬性,可能會導致非預期的副作用(?),取而代之的是使用before_create
或是更之前的callback。
但有時物件的資訊要等到save之後才存在(譬如說id
),如果需要這個id
來產生某些關聯性的data,那可能就需要使用after_save
callback。
另外在搜尋資料的過程也發現,關於after_save
,需要更小心的使用,其實在after_save
的時候資料還未被實在的寫入資料庫。以下模擬一個物件存取的過程。
def save(*args)
ActiveRecord::Base.transaction do
self.before_validation
self.validate!
self.after_validation
self.before_save
db_connection.update(self, *args)
self.after_save
end
self.after_commit
end
這告訴我們關於after_save
的兩件事
在某些情況下,這樣的特性可能有問題
class Shipment < ApplicationRecord
after_save :notify_client, if: proc { saved_change_to_status? }
def notify_client
Email::Service.send_status_update_email(id)
end
end
在上面這段程式中,如果after_save 的方法出錯的話,整個存取動作會被倒回,如果不想要有這種特性的話,最好是使用after_commit
來取代。
如果需要在存取之後更新一個物件會需要額外的資料庫執行,所以如果需要更新物件的屬性(attribute),使用before_save
會是比較有效率的選擇。
但有時物件的資訊要等到save之後才存在(譬如說id
),如果需要這個id
來產生某些關聯性的data,那可能就需要使用after_save
callback。
1.Rubyguide-ActiveRecord Callbacks
2.53 Ruby on Rails Interview Questions and Answers
3.How to Safely Use ActiveRecord’s after_save