2012-02-16 15 views
6

Importuję rekordy zbiorczo i nie chcę aktualizować licznika za każdym razem. Chcę pominąć aktualizacje sql counter_cache podczas bulk upsert, a następnie wywołać reset_counters na końcu pętli.Jak wyłączyć powiązanie Railsowanie counter_cache w czasie wykonywania

Próbowałem:

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! 

ale widzę na wyjściu sql że wciąż aktualizując counter_cache.

uwaga: nie można użyć ActiveRecord-import, ponieważ chcę, aby wykonać upserts i używam PostgreSQL

+0

Rozwiązałeś to? Taki sam problem... –

Odpowiedz

5

masz kilka różnych opcji omijając aktualizację pamięci podręcznej licznik, a jedno z nich wybrać tak naprawdę zależy od tego, jak chcesz uporządkować swoją aplikację. Omówię różne sposoby, w jakie można obejść pamięć podręczną licznika i wspomnieć o niektórych uwagach, które możesz chcieć w tym kontekście zrobić.

Zasadniczo istnieją trzy różne sposoby można pominąć aktualizację pamięci podręcznej Licznik:

  1. Monkey patch your model to disable the counter cache callback
  2. Use an update method that doesn't trigger callbacks
  3. zdefiniowania alternatywnego modelu skierowana do tej samej tabeli, która nie ma takie samo działanie oddzwaniania i użyj go, gdy zbiorcze wstawianie do bazy danych

Pamiętaj, że pierwsze dwie powyższe opcje to więcej związane z wyłączaniem wywołań zwrotnych w ActiveRecord, a to ma sens, ponieważ pamięć podręczna licznika jest zaimplementowana wewnętrznie za pomocą wywołania zwrotnego.

Gdy Railsy ładują model, który ma powiązania z pamięcią podręczną licznika, dynamicznie definiuje metody wywołania zwrotnego. Jeśli chcesz je wyłączyć jako wywołanie zwrotne, najpierw musisz dowiedzieć się, jakie są nazwy wywołań zwrotnych.

Istnieją dwa podstawowe sposoby ustalania, jakie metody zostały zdefiniowane przez Railsy w celu wdrożenia tych wywołań zwrotnych. Możesz czytać źródło Railsów, aby znaleźć nazwy, które zamierzasz wygenerować poprzez Intorpolation String, lub możesz użyć introspekcji, aby dowiedzieć się, na jakie metody odpowiada twoja klasa. Podam przykład, w jaki sposób można użyć introspekcji, aby znaleźć oddzwonienia zdefiniowane przez ActiveRecord w celu automatycznego zaimplementowania buforowania licznika.

Załóżmy, że masz klasę o nazwie SpecialReply, która pochodzi z klasy Reply, która pochodzi z ActiveRecord :: Base (this example comes from the test suite with Rails). Ma mieć kolumnę licznik cache, jak określono poniżej:

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

W konsoli można zobaczyć, jakie metody klasa odpowiada za pomocą .methods. To będzie produkować dużo hałasu, ponieważ każdy przypadek Object reaguje już na wiele sposobów, więc można zawęzić listę następująco:

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

W drugiej linii mówisz pokaż wszystkie metody, na które reaguje moja instancja SpecialReply, minus te, na które reagują wszystkie Obiekty. Często pomaga to w introspekcji, odfiltrowując metody, które nie są związane z typem klasy, który przeglądasz.

Niestety, nawet po tym filtrowaniu jest dużo szumu ze względu na metody, które ActiveRecord dodaje do wszystkich swoich klas potomnych. W tym przypadku grep jest przydatna - od ActiveRecord usłużnie tworzy licznik metod zwrotnych zawierających ciąg counter_cache (see the meta-programming used by ActiveRecord to generate a counter cache method for a belongs_to association), można dowiedzieć się callbacków zdefiniowane podobne do przeciwdziałania bufory z następującymi zasadami:

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

Zauważ, że ponieważ grep działa na a String, i methods zwraca tablicę nazw metod symboli, najpierw używamy to_proc (&:) w celu konwertowania wszystkich symboli na ciągi, a następnie grep tych zawierających counter_cache. To pozostawia mnie z następujących metod, które wydają się jakby były one prawdopodobnie generowane automatycznie przez ActiveRecord jako wywołania zwrotne do wdrożenia licznika buforowanie:

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 

powinieneś być w stanie śledzić podobny proces w programie do określenia nazwy metod dodanych przez ActiveRecord, dzięki czemu można je znokautować po existing instructions for removing callbacks.

Twój wybór spośród powyższych opcji zależy od struktury programu i kompromisów, które chcesz rozważyć dla zwiększenia efektywności ładowania danych. Warto zauważyć, że pierwsze dwie opcje mogą sprawić, że twój kod stanie się mniej czytelny, modyfikując zachowanie klasy z zewnątrz (łatanie małp) i może spowodować niestabilność twojego systemu, pomijając reguły biznesowe (aktualizacje kolumn z pamięcią podręczną) na temat aktualizacji danych. Z tych powodów zastanawiałbym się, czy możesz stworzyć inną klasę do ładowania danych w zoptymalizowany sposób, minimalizując wpływ na czytelność lub spójność danych.

Powiązane problemy