2017-06-10 14 views
0

私はレールの組み込みcounter_cacheの関連付けをインクリメント/デクリメントカウントに使用するモデルを用意しています。私は特定の状況のた​​めにモデルを破壊するときにこれを無効にする必要があるという要件があります。私はModel.skip_callback(:destroy, :belongs_to_counter_cache_after_update)のようなことをしようとしましたが、期待通りに動作していないようです(つまり、関連付けられているモデルのデクリメントが終了します)。任意の有用なポインタが評価されます。あなたがモデルのあなたのオブジェクトを破壊するので、前skip_counter_cache_updateのために、ちょうど設定された値をskip rails counter_cache update

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を使用することができます。delete' –

+0

コールバックをスキップする方法はわかっていますが、カウンターコールバックだけを無効にする必要があります。今のところ、私は 'destroy_all'を使っていて、カウンターをリセットしています(無駄に思えます)。 –

答えて

0

あなたは、コールバックが実行されなければならないときを決定するようなものをフラグを作成することができ

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

デクリメントコールバックは実行されません。

+0

デクリメントカウンタキャッシュへのコールバックはレールに組み込まれており、独自のカウンタメソッドを作成するのではなく、そのカウンタを無効にしたいと考えています。 –

0

1つの方法は、破棄の際にキャッシュカウントを更新する方法を一時的に無効にすることです。たとえば あなたは二つのモデル

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 

を(カウンタキャッシュの更新をスキップする)あなたはどんな製品オブジェクトを破壊するならば、それはカテゴリー内のカウンタキャッシュは更新されません一時的に何もしない1つの偽の方法でこのメソッドをオーバーライドすることにしました表。 しかし、コードを実行して特定のオブジェクトを破棄した後、実際のメソッドを復元することは非常に重要です。あなたは、特定のタスクを破壊した後、あなたは両方のオーバーライドを実行し、コード

を復元することを確認しますクラスのメソッドを、書くことができるメソッドの定義が常に復元することを確実にするために

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 

を次の操作を行うことができ、実際のクラスメソッドに復元するには与えられたとして、あなたは

Product.without_counter_cache_update_on_destroy { Product.last.destroy } 

以下いずれかの製品のオブジェクトを破壊する場合

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 

今では、カテゴリーテーブル内のカウンタキャッシュは更新されません。

参考文献:
無効化ActiveModelコールバックhttps://jeffkreeftmeijer.com/2010/disabling-activemodel-callbacks/ 一時的なオーバーライドメソッド:https://gist.github.com/aeden/1069124