2012-02-16 9 views
6

レコードを一括してインポートしており、毎回カウンタを更新したくありません。一括アップアップ中にcounter_cache SQLアップデートをスキップして、ループの最後にreset_countersを呼び出したいとします。実行時にRailsアソシエーションのcounter_cacheを無効にする方法

私が試してみました:

my_model = MyModel.find_or_initialize_by_slug row[:slug] 
my_model.association(:my_association).reflection.options[:counter_cache] = false 
my_model.attributes = {:name => "Christopher"} 
my_model.save! 

を私はそれがまだcounter_cacheを更新していますことを、SQL出力で見ることができます。

注:私はアップサートを実行したいと私はあなたがカウンターキャッシュの更新をスキップするため、いくつかの異なるオプションを持っているPostgreSQLの

+0

これを解決しましたか?同じ問題... –

答えて

5

を使用して、あなたが選択した一人ですので、私はActiveRecordのインポートを使用することはできません実際にアプリケーションをどのように構造化したいかによって異なります。私はあなたがカウンターのキャッシュの周りに得ることができるさまざまな方法について議論し、あなたがそうしたいと思っているかもしれないいくつかの考察を述べます。

基本的に、あなたはカウンターキャッシュの更新をスキップすることができ、3つの異なる方法があります。

  1. Monkey patch your model to disable the counter cache callback
  2. Use an update method that doesn't trigger callbacks
  3. はありません同じテーブルを指している代替モデルを定義します同じコールバック動作を使用し、データベースに一括挿入するときに使用します。

上記の最初の2つのオプションは、 ActiveRecordのコールバックを無効にすることに関連しています。これは、カウンタキャッシュがコールバックを使用して内部的に実装されるため意味があります。

Railsがカウンタキャッシュとの関連付けを持つモデルを読み込むと、コールバックメソッドが動的に定義されます。これらをコールバックとして無効にする場合は、最初にコールバック名が何であるか把握する必要があります。

これらのコールバックを実装するためにRailsが定義したメソッドを理解するには、主に2つの方法があります。 Railsソースを読み込んで、String intorpolationによって生成される名前を調べるか、イントロスペクションを使用してクラスがどのメソッドに応答するかを調べることができます。イントロスペクションを使用してカウンタキャッシュを自動的に実装するために、ActiveRecordで定義されたコールバックを調べる方法の例を示します。

ActiveRecord :: Base(this example comes from the test suite with Rails)に由来するReplyクラスを基にしたSpecialReplyというクラスがあるとしましょう。コンソールで

class SpecialReply < ::Reply 
    belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count' 
end 

、あなたはあなたのクラスが.methodsを使用してに反応するものを見ることができます方法:以下に定義するように、それはカウンターキャッシュ列を持っています。これはObjectのすべてのインスタンスが既にメソッドの多くに対応しているので、多くのノイズを生成するために起こっているので、次のようにリストを絞り込むことができます。

1.9.3-p194 :001 > sr = SpecialReply.new 
1.9.3-p194 :002 > sr.methods - Object.methods 

をあなたが言っている二行目、ショーで私のSpecialReplyのインスタンスが応答するメソッドのすべてを、すべてのオブジェクトが応答するメソッドから除外します。これは、あなたが見ているクラスタイプに特有ではないメソッドを除外することで、イントロスペクションに役立ちます。

残念ながら、このフィルタリングの後でさえ、ActiveRecordがすべての子孫クラスに追加するメソッドのために、多くのノイズが発生します。この場合、grepは便利です - ActiveRecordのが親切文字列counter_cachesee the meta-programming used by ActiveRecord to generate a counter cache method for a belongs_to association)を含むカウンタコールバックメソッドを作成するので、あなたは次のようにキャッシュに対抗するために関連する定義されたコールバックを見つけることができます:grep以降に動作することを

1.9.3-p194 :001 > sr = SpecialReply.new 
1.9.3-p194 :002 > sr.methods.map(&:to_s).grep(/counter_cache/) 

お知らせ文字列であり、methodsはシンボルメソッド名の配列を返します。最初にto_proc&:)を使用して、すべてのシンボルを文字列に変換してから、counter_cacheを含むシンボルをグレープします。それは、彼らはおそらく、自動生成のActiveRecordによるカウンタのキャッシュを実装するためのコールバックとしてだったように思える次の方法で私を残します:

belongs_to_counter_cache_after_create_for_special_topic 
belongs_to_counter_cache_before_destroy_for_special_topic 
belongs_to_counter_cache_after_create_for_topic 
belongs_to_counter_cache_before_destroy_for_topic 
belongs_to_counter_cache_after_create_for_topic_with_primary_key 
belongs_to_counter_cache_before_destroy_for_topic_with_primary_key 

あなたが追加したメソッド名を決定するために、あなたのプログラムで同様のプロセスをたどることができるはずですActiveRecordによって、existing instructions for removing callbacksの後にそれらをノックアウトできるようにします。

上記のオプションからの選択は、プログラムの構造と、データの読み込み効率の向上を考慮するトレードオフによって決まります。最初の2つのオプションは、クラスの動作を外部から変更することでコードを読みにくくすることができ、データの更新時にビジネスルール(キャッシュ列の更新)をバイパスすることでシステムを不安定にする可能性があります。このような理由から、データの可読性やデータの一貫性への影響を最小限に抑えながら、最適化された方法でデータをロードするための別のクラスを作成できるかどうかについて考えています。

関連する問題