Ruby on Rails:: incluir en una asociación polimórfica con submodelos
Pregunta
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 con entusiasmo los vencimientos cuando cargo c, porque sé que necesitaré hasta el último de ellos.¿Hay alguna manera de hacerlo?Simplemente definir un :include regular me genera errores porque no todos los tipos adjuntos tienen una caducidad de submodelo.
Solución
Respuesta editada
Recientemente descubrí que Rails admite la carga ansiosa de asociaciones polimórficas cuando filtras por la columna de tipo polimórfico.Por tanto, no es necesario 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)
Antigua respuesta
Este es un truco ya que no existe una forma directa de incluir 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 da como resultado 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 un conjunto de columnas diferente para diferentes tipos de contenido.
Advertencia: Las asociaciones ficticias en Content
La clase no debe usarse directamente ya que generará resultados inesperados.
P.ej:Digamos que el primer objeto en el contents
La mesa contiene comida.
Content.first.food # will work
Content.first.thing
La segunda llamada no funcionará.Podría darte un Thing
objeto con la misma identificación que el Food
objeto señalado por Content
.