ruby-on-rails include polymorphic-associations eager-loading rails-activerecord

Ruby on Rails: incluye una asociación polimórfica con submodelos



ruby-on-rails include (1)

Cuando se trabaja con una asociación polimórfica, ¿es posible ejecutar una inclusión en submodelos que solo están presentes en algunos tipos?

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 cargar las expiraciones cuando cargue c, porque sé que necesitaré cada una de ellas. ¿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 editada

Recientemente descubrí que Rails admite una carga ansiosa 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 consulta el 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)

Vieja respuesta

Esto es un truco ya que no hay una forma directa de 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 consulta el 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)

Eso resulta en dos llamadas SQL a la base de datos (en realidad son 4 llamadas ya que rails ejecuta un SQL por cada :include )

No hay forma de hacer esto en un SQL ya que necesita diferentes conjuntos de columnas para diferentes tipos de contenido.

Advertencia: las asociaciones ficticias en la clase de Content no se deben usar directamente, ya que generarán resultados inesperados.

Por ejemplo: digamos que el primer objeto en la tabla de contents contiene comida.

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 señalado por el Content .