6

此代碼是否線程安全?Rails 3 ActiveRecord .skip_callback線程安全

MyModel.skip_callback(:save, :before, :my_callback) 
my_model_instance.update_attributes(attributes) 
MyModel.set_callback(:save, :before, :my_callback) 

我可以安全地使用它來避免重新觸發相同的回調嗎?

下面是一個例子

class Blog < ActiveRecord::Base 

    after_save :update_blog_theme, :if => :active_theme_id_changed? 

    # ... 

    private 

    def update_blog_theme 

    # Reuses a previously used BlogTheme or creates a new one 
    blog_theme = BlogTheme.find_by_theme_id_and_blog_id(
         self.active_theme_id, 
         self.id) 

    blog_theme ||= BlogTheme.create!( 
        :theme_id => active_theme_id, 
        :blog_id => self.id) 

    Blog.skip_callback(:save, :after, :update_blog_theme) 
    self.update_attributes!(:active_blog_theme_id => blog_theme.id) 
    Blog.set_callback(:save, :after, :update_blog_theme) 

    end 

end 
+0

似乎哈克,你爲什麼不能使用before_save或before_create:上面提到的兩種寶石在阿南德的帖子在這裏與其他可能選項一起上市? – apneadiving

+0

最終要求是什麼? – Anatoly

+0

這裏沒有要求,我沒有使用這個代碼,也許我永遠不會這樣做,但是我已經在互聯網上找到了這個解決方案,並問我自己是否可以安全地在多線程中使用 – mcasimir

回答

5

skip_callbackset_callback都不是線程安全的。我可以在嘗試在sidekiq(一個線程化的異步作業處理器)中創建一些記錄時確認這一點。只要我重新啓用回調,就會有一個競爭條件導致回調被調用。如果我評論回調重新激活代碼,則沒有問題。

我已經找到了一些可能的解決方案的問題,包括兩種寶石:

  • 的「偷偷摸摸保存」寶石
  • 的「skip_activerecord_callbacks」寶石

偷偷摸摸保存寶石似乎是這裏最直接,最有意向的選擇。 gem基本上繞過了ActiveRecord持久化方法並執行直接的sql。

這也是我唯一可以自信地說是線程安全的。這也是一個非常小和可以理解的寶石。缺點是它不稱爲驗證。因此您需要自己致電驗證。

Anand A. Bait在數字選項上放了一個很好的概要。我懷疑所有五個選項都是線程安全的。 http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/