10

Al trabajar con una asociación polimórfica, ¿es posible ejecutar una inclusión en submodelos que solo están presentes en algunos tipos?Ruby on Rails:: incluir en una asociación polimórfica con submodelos

Ejemplo:

class Container 
    belongs_to :contents, :polymorphic => true 
end 
class Food 
    has_one :container 
    belongs_to :expiration 
end 
class Things 
    has_one :container 
end 

En la vista voy a querer hacer algo como:

<% c = Containers.all %> 
<% if c.class == Food %> 
    <%= food.expiration %> 
<% end %> 

Por lo tanto, me gustaría carga ansiosos los vencimientos cuando la carga hasta C porque sé que necesitaré cada uno de ellos. ¿Hay alguna manera de hacerlo? Simplemente definir un regular: include me da errores porque no todos los tipos incluidos tienen una caducidad de submodelo.

Respuesta

24

respuesta Editado

Hace poco descubrió que Rails soporta la carga con ganas de asociaciones polimórficas cuando filtra por la columna de tipo polimórfico. Entonces no hay necesidad de declarar asociaciones falsas.

class Container 
    belongs_to :content, :polymorphic => true 
end 

Ahora consultar la Container por container_type.

containers_with_food = Container.find_all_by_content_type("Food", 
          :include => :content) 

containers_with_thing = Container.find_all_by_content_type("Thing", 
          :include => :content) 

respuesta Antiguo

Este es un truco que no hay manera directa para incluir los objetos polimórficos en una consulta.

class Container 
    belongs_to :contents, :polymorphic => true 
    # add dummy associations for all the contents. 
    # this association should not be used directly 
    belongs_to :food 
    belongs_to :thing 
end 

Ahora consultar la Container por container_type.

containers_with_food = Container.find_all_by_content_type("Food", 
          :include => :food) 

containers_with_thing = Container.find_all_by_content_type("Thing", 
          :include => :thing) 

que da lugar a dos llamadas SQL a la base de datos (en realidad es de 4 llamadas como carriles ejecuta un SQL para cada :include)

No hay manera de hacer esto en un SQL como sea necesario diferente columna establecer para diferentes tipos de contenido.

Advertencia: Las asociaciones ficticias en la clase Content no deben usarse directamente, ya que provocarán resultados inesperados.

E.g: Digamos que el primer objeto en la tabla contents contiene alimentos.

Content.first.food # will work 
Content.first.thing 

La segunda llamada no funcionará. Podría darle un objeto Thing con la misma identificación que el objeto Food apuntado por Content.

+0

He actualizado mi respuesta sobre la base de nueva información, eche un vistazo. –

+1

¿En qué versión de ActiveRecord funciona la carga ansiosa de asociaciones polimórficas? No funciona para mí en 3.2.3 – nicholaides

+0

@nicholaides Debería funcionar en 3.2.3. La carga ansiosa ocurre solo cuando filtra por la columna de tipo polimórfico. ¿Cuál es el error que encontraste? –