2012-02-16 7 views
6

Importación de registros a granel y no quiero actualizar el contador cada vez. Quiero omitir las actualizaciones counter_cache sql durante la inserción masiva y llamar al reset_counters al final del ciclo.Cómo deshabilitar la asociación de Rails counter_cache en el tiempo de ejecución

que he intentado:

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! 

pero puedo ver en la salida de SQL que sigue actualizando la counter_cache.

nota: no se puede utilizar activerecord a importar porque quiero realizar upserts y estoy usando PostgreSQL

+0

¿Has resuelto esto? El mismo problema... –

Respuesta

5

Usted tiene algunas opciones diferentes para saltarse una actualización de la memoria caché de venta libre, y el que usted elija realmente depende de cómo quiera estructurar su aplicación. Discutiré las diferentes formas en que puede sortear el contador de caché y mencionar algunas de las consideraciones que puede querer hacer al hacerlo.

Básicamente, hay tres formas diferentes que puede omitir la actualización de la memoria caché contador:

  1. Monkey patch your model to disable the counter cache callback
  2. Use an update method that doesn't trigger callbacks
  3. definir un modelo que apunta alternativa a la misma mesa que no tiene la mismo comportamiento de devolución de llamada, y usar eso cuando la inserción masiva en la base de datos

Tenga en cuenta que las dos primeras opciones anteriores son más g generalmente relacionado con la desactivación de devoluciones de llamadas en ActiveRecord, y esto tiene sentido porque el contador de caché se implementa internamente mediante una devolución de llamada.

Cuando Rails carga un modelo que tiene asociaciones con un contador de caché, define dinámicamente los métodos de devolución de llamada. Si desea deshabilitar estos como una devolución de llamada, primero debe averiguar cuáles son los nombres de devolución de llamada.

Existen dos formas principales de averiguar qué métodos Rails ha definido para implementar estas devoluciones de llamada. Puede leer la fuente de Rails para averiguar los nombres que va a generar a través de la intorpolación de String, o puede usar la introspección para descubrir a qué métodos responde su clase. Daré un ejemplo de cómo puede usar la introspección para averiguar las devoluciones de llamada definidas por ActiveRecord para implementar automáticamente el almacenamiento en caché.

Supongamos que tiene una clase llamada SpecialReply que desciende de una clase de respuesta que desciende de ActiveRecord :: Base (this example comes from the test suite with Rails). Tiene una columna de caché mostrador como se define a continuación:

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

En la consola, se puede ver lo que los métodos de la clase responde a mediante el uso de .methods. Esto va a producir una gran cantidad de ruido, ya que cada instancia de Object ya responde a una gran cantidad de métodos, por lo que puede reducir la lista de la siguiente manera:

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

En la segunda línea que está diciendo, espectáculo todos los métodos a los que responde mi instancia de SpecialReply, menos aquellos a los que responden todos los objetos. Esto a menudo ayuda con la introspección al filtrar métodos que no son particulares del tipo de clase que estás viendo.

Desafortunadamente, incluso después de este filtrado hay mucho ruido debido a los métodos que ActiveRecord agrega a todas sus clases descendientes. En este caso grep es útil - ya ActiveRecord amablemente crea métodos de devolución de llamada de venta libre que contienen la cadena counter_cache (see the meta-programming used by ActiveRecord to generate a counter cache method for a belongs_to association), se puede averiguar las devoluciones de llamada definidos relacionados para contrarrestar cachés con lo siguiente:

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

en cuenta que ya grep opera en una Cadena, y methods devuelve una matriz de nombres de métodos de símbolos, primero usamos un to_proc (&:) para convertir todos los Símbolos a Cadenas y luego eliminar los que contienen counter_cache. Eso me deja con los siguientes métodos que parecen que fueron probablemente auto-generado por ActiveRecord como devoluciones de llamada para la implementación de contador de almacenamiento en caché:

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 

usted debería ser capaz de seguir un proceso similar en su programa para determinar los nombres de los métodos añadidos por ActiveRecord para que pueda eliminarlos después de existing instructions for removing callbacks.

Su elección entre las opciones anteriores realmente depende de la estructura de su programa, y ​​las compensaciones que está dispuesto a considerar para una mayor eficiencia de carga de datos. Digno de mención es que las dos primeras opciones pueden hacer que su código sea menos legible modificando el comportamiento de una clase desde afuera (parche de mono) y puede hacer que su sistema sea inestable evitando las reglas comerciales (actualizaciones de las columnas de caché) en las actualizaciones de datos. Por estas razones, pensaría si podría crear otra clase para cargar sus datos de una manera optimizada, al tiempo que minimiza los impactos sobre la legibilidad o la coherencia de los datos.

Cuestiones relacionadas