Ruby on Rails: :include on a polymorphic association with submodels

ぃ、小莉子 提交于 2019-11-27 02:19:32

问题


When working with a polymorphic association, is it possible to run an include on submodels that are only present in some types?

Example:

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

In the view I'm going to want to do something like:

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

Therefore, I'd like to eager load the expirations when I load up c, because I know I will need every last one of them. Is there any way to do so? Just defining a regular :include gets me errors because not all enclosed types have a submodel expiration.


回答1:


Edited Answer

I recently found out that Rails supports eager loading of polymorphic associations when you filter by the polymorphic type column. So there is no need to declare fake associations.

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

Now query the Container by 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)

Old Answer

This is a hack as there is no direct way to include the polymorphic objects in one query.

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

Now query the Container by 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)

That results in two SQL calls to the database ( actually it is 4 calls as rails executes one SQL for every :include)

There is no way to do this in one SQL as you need different column set for different content types.

Caveat: The dummy associations on Content class should not be used directly as it will result in unexpected results.

E.g: Lets say the first object in the contents table contains food.

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

The second call will not work. It might give you a Thing object with the same id as the Food object pointed by Content.



来源:https://stackoverflow.com/questions/2390017/ruby-on-rails-include-on-a-polymorphic-association-with-submodels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!