2017-06-10 101 views
0

我有一個使用rails的內置counter_cache關聯來增加/減少計數的模型。我有一個要求,我需要在特定情況下銷燬模型時禁用此功能。我試圖做一些類似於Model.skip_callback(:destroy, :belongs_to_counter_cache_after_update)的事情,但它似乎沒有像預期的那樣工作(即,它仍然最終減少相關模型)。任何有用的指針,將不勝感激。爲skip_counter_cache_update跳過導軌counter_cache更新

class YourModel 
    attr_accessor :skip_counter_cache_update 

    def decrement_callback 
    return if @skip_counter_cache_update 
    # Run callback to decrement counter cache 
    ... 
    end 
end 

你摧毀你的模型的對象,因此前,只需設定值:

+0

如果你確定以跳過所有回調,您可以用'Model.first。刪除' –

+0

是的我知道方法來跳過回調,但我有一個特殊的需要,只禁用計數器回調。現在,我使用'destroy_all',然後重置計數器(這看起來很浪費)。 –

回答

0

您可以創建一個標誌,以決定何時回調應該來說,像

@object = YourModel.find(some_id) 
@object.skip_counter_cache_update = true 
@object.destroy 

所以它不會運行遞減回調。

+0

遞減計數器緩存的回調內置到rails中,我想禁用它而不是創建自己的計數器方法。 –

0

一種選擇是臨時覆蓋負責更新緩存計數的方法,以防銷燬。 例如,如果你有以下兩種模式

class Category < ActiveRecord::Base 
    has_many :products 
end 

class Product < ActiveRecord::Base 
    belongs_to :category, counter_cache: true 
end 

現在,你可以嘗試找到負責更新緩存的方法有以下

2.1.5 :038 > Product.new.methods.map(&:to_s).grep(/counter_cache/) 

指望這表明所有這些都是counter_cache相關產品的實例方法與結果如下

=> ["belongs_to_counter_cache_before_destroy_for_category", "belongs_to_counter_cache_after_create_for_category", "belongs_to_counter_cache_after_update_for_category"] 

從方法的名稱就說明

"belongs_to_counter_cache_after_create_for_category" 

可能在銷燬後負責計數器緩存更新。 所以我決定暫時覆蓋此方法以一個假的方法,它不會做任何事情(跳過櫃檯緩存更新)

Product.class_eval do 
    def fake_belongs_to_counter_cache_before_destroy_for_category; end 
    alias_method :real_belongs_to_counter_cache_before_destroy_for_category, :belongs_to_counter_cache_before_destroy_for_category 
    alias_method :belongs_to_counter_cache_before_destroy_for_category, :fake_belongs_to_counter_cache_before_destroy_for_category 
end 

現在,如果你將摧毀任何產品的對象,也不會更新分類計數緩存表。 但是,在運行代碼來銷燬特定對象之後,恢復實際方法非常重要。要恢復到實際的類方法,你可以做以下

Product.class_eval do 
    alias_method :belongs_to_counter_cache_before_destroy_for_category, :real_belongs_to_counter_cache_before_destroy_for_category 
    remove_method :real_belongs_to_counter_cache_before_destroy_for_category 
    remove_method :fake_belongs_to_counter_cache_before_destroy_for_category 
end 

爲了確保方法定義總是恢復後您的具體銷燬任務,你可以寫一個類的方法,這將確保同時運行倍率和恢復代碼

class Product < ActiveRecord::Base 
    belongs_to :category, counter_cache: true 

    def self.without_counter_cache_update_on_destroy(&block) 
    self.class_eval do 
     def fake_belongs_to_counter_cache_before_destroy_for_category; end 
     alias_method :real_belongs_to_counter_cache_before_destroy_for_category, :belongs_to_counter_cache_before_destroy_for_category 
     alias_method :belongs_to_counter_cache_before_destroy_for_category, :fake_belongs_to_counter_cache_before_destroy_for_category 
    end 
    yield 
    self.class_eval do 
     alias_method :belongs_to_counter_cache_before_destroy_for_category, :real_belongs_to_counter_cache_before_destroy_for_category 
     remove_method :real_belongs_to_counter_cache_before_destroy_for_category 
     remove_method :fake_belongs_to_counter_cache_before_destroy_for_category 
    end 
    end 
end 

現在,如果你摧毀任何產品對象給出以下

Product.without_counter_cache_update_on_destroy { Product.last.destroy } 

它不會更新類別表計數器緩存。

參考文獻:
加載ActiveModel禁用回調https://jeffkreeftmeijer.com/2010/disabling-activemodel-callbacks/ 臨時覆蓋方法:https://gist.github.com/aeden/1069124