2012-02-16 16 views
6

我正在批量導入記錄,並且不希望每次都更新計數器。我想在批量upsert中跳過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! 

,但我可以在SQL輸出中看到,它仍然是更新counter_cache。

注:因爲我想執行upserts我不能使用ActiveRecord的進口,我使用PostgreSQL

+0

你解決了這個問題嗎?同樣的問題... – 2012-10-28 18:21:19

回答

5

您有跳過櫃檯緩存的更新幾個不同的選項,你所選擇的一個真的取決於你想如何構建你的應用程序。我將討論您可以在計數器緩存中獲得的不同方式,並提及您可能想要這樣做的一些注意事項。

基本上有三種不同的方式,你可以跳過櫃檯緩存的更新:

  1. Monkey patch your model to disable the counter cache callback
  2. Use an update method that doesn't trigger callbacks
  3. 定義了另一種模式指向不具有相同的表相同的回調行爲,並在批量插入數據庫時​​使用該方法

請注意,上面的前兩個選項更多通常與禁用ActiveRecord中的回調有關,這很有意義,因爲計數器緩存是通過回調內部實現的。

當Rails加載與計數器緩存關聯的模型時,它會動態地定義回調方法。如果你想禁用這些作爲回調,你必須先弄清楚回調名稱是什麼。

確定Rails爲了實現這些回調所定義的方法有兩種主要方法。您可以通過閱讀Rails源代碼來找出它將通過String intorpolation生成的名稱,或者您可以使用introspection來找出您的類響應的方法。我將舉例說明如何使用自省來找出由ActiveRecord定義的回調,以便自動實現計數器緩存。

假設您有一個名爲SpecialReply的類,該類是從ActiveRecord :: Base(this example comes from the test suite with Rails)下降的Reply類繼承而來的。它有一個計數器緩存列定義如下:

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),你可以找出定義相關的回調計數器,具有以下緩存計數器回調方法:

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

注意,因爲grep操作上一個字符串,並且methods返回符號方法名稱數組,我們首先使用to_proc&:)將所有符號轉換爲字符串,然後將包含counter_cache的符號轉換爲grep。這給我留下了下列方法,看起來他們很可能是自動生成的的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

您從上述選項中選擇真正取決於程序的結構,以及您願意考慮的權衡以提高加載數據的效率。值得注意的是,前兩個選項可以通過修改外部類的行爲(猴子修補)來降低代碼的可讀性,並且可以繞過數據更新的業務規則(更新緩存列)而使系統不穩定。出於這些原因,我會考慮是否可以創建另一個類以優化方式加載數據,同時最大限度地減少對可讀性或數據一致性的影響。

相關問題