2009-09-03 10 views
38

¿Alguien sabe una forma de determinar si una asociación de Rails ha sido cargada ansiosamente?Cómo determinar si la Asociación de rieles está cargada de entusiasmo?

Mi situación: Tengo un conjunto de resultados donde a veces una de las asociaciones está ansiosamente cargada, y otras no. Si no está lleno de ansias, entonces quiero buscar asociaciones usando la búsqueda de ActiveRecord. Si está ansiosamente cargada, quiero usar detectar.

Por ejemplo, supongo que tengo una matriz "has_many" de objetos shipping_info en mi modelo de artículo. Entonces:

Si el artículo está ansioso cargado, la carga más eficiente es:

item.shipping_infos.detect { |si| si.region == "United States" } 

Si el artículo no está dispuesto cargado de carga, más eficiente es:

item.shipping_infos.where(region: "United States").first 

Pero a menos que sepa si está ansiosamente cargada, no sé qué código llamar para obtener el registro de manera eficiente. Si utilizo el primer método cuando no estaba ansioso de cargar, entonces tengo que buscar más registros de DB de los necesarios. Y si utilizo el segundo método cuando estaba ansioso de cargar, mis ansiosos objetos cargados se ignoran.

Respuesta

41

item.shipping_infos.loaded? le dirá.

Tengo que decir, sin embargo: este camino conduce a la locura ... antes de escribir código que pruebe loaded? que decidir entre #detect y #find, asegúrese de que esta instancia realmente materia, en relación con todo lo que está pasando.

Si esto no es lo más lento que hace su aplicación, la adición de rutas de código adicionales agrega complejidad innecesaria. El hecho de que pueda desperdiciar un poco de esfuerzo en la base de datos no significa que deba solucionarlo, probablemente no importe de manera medible.

+0

Gracias Bryan. Entiendo de dónde vienes. Sin embargo, este código en particular se encuentra en el parcial más frecuentemente llamado en toda nuestra aplicación, por lo que eliminar incluso microsegundos hace una diferencia medible. Le daré #loaded? un intento. – wbharding

+9

¡Esto solo funcionará para las asociaciones has_many! En el caso de belongs_to esta llamada cargará realmente el otro objeto (por lo que siempre será cierto) – reto

2

Eche un vistazo a Bullet gem.. Esto le dirá cuándo debe y no debe usar la carga ansiosa.

+0

Bullet ha demostrado ser realmente útil, aunque he hecho muy pocas otras optimizaciones de DB todavía. Al menos se deshace de algunas líneas innecesarias en la salida de la consola. ;) – lime

+0

El enlace del complemento de viñetas está muerto. –

3

Puede detectar si se ha cargado o no una sola asociación con loaded_ foo?. Por ejemplo, si shipping_info era una asociación belongs_to, entonces item.loaded_shipping_info? volverá verdadero cuando haya sido ansiosamente cargado. Curiosamente, parece devolver nil (en lugar de falso) cuando no se ha cargado (en Rails 2.3.10 de todos modos).

+3

Esto se ha eliminado en Rails 3.1: https://github.com/rails/rails/issues/472 – Forrest

2

solución a este problema debe ser foo.association(:bla).loaded?, pero funciona incorrectamente - comprueba y asociación marcas como sucio:

class Foo; has_one :bla, :autosave => true end 
foo.association(:bla).loaded? #=> false 
foo.save # saves foo and fires select * from bla 

Así que he añadido a la siguiente extensión ActiveRecord:

module ActiveRecord 
    class Base 
    def association_loaded?(name) 
     association_instance_get(name).present? 
    end 
    end 
end 

y ahora:

class Foo; has_one :bla, :autosave => true end 
foo.association_loaded?(:bla) #=> false 
foo.save # saves foo 
+0

Debería comprobar que esto sigue siendo un problema y actualizar la respuesta para adaptarlo a las versiones de Rails correspondientes. No pude reproducir –

+0

Todavía hay un problema desde Rails 4.2.6. No estoy seguro si Rails 5 lo tiene. – Omnilord

+0

¿Cuál es la consecuencia de marcarlo como sucio? ¿Solo una declaración extra adicional? ¿O hay más daño a eso? – lulalala

19

Yo sugeriría usar item.association_ cache.keys que proporcionará una lista de las asociaciones cargadas ansiosas. ¿Así que incluye item.association_cache.keys.include?: name_of_association

+1

Solución perfecta. Dabogert eres el rey :) – Benj

+0

Wow, no puedo creer que me haya estado perdiendo esto. Esto funciona para casos donde la asociación NO está cargada, pero HAY una memoria caché en memoria (por ejemplo, cuando construyes un objeto usando la asociación). –

Cuestiones relacionadas