Ruby on Rails ::包含与子模型的多态关联

时间:2010-03-05 21:19:54

标签: ruby-on-rails include polymorphic-associations eager-loading rails-activerecord

使用多态关联时,是否可以在仅存在于某些类型中的子模型上运行包含?

示例:

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

在视图中,我想要做类似的事情:

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

因此,当我加载c时,我想急切加载到期,因为我知道我将需要最后一个。有没有办法这样做?只是定义一个常规:include会给我带来错误,因为并非所有封闭类型都有子模型到期。

1 个答案:

答案 0 :(得分:24)

已编辑的答案

我最近发现当你按多态类型列过滤时,Rails支持急切加载多态关联。所以没有必要声明假联想。

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

现在按Container查询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)

旧答案

这是一个黑客攻击,因为没有直接的方法可以在一个查询中包含多态对象。

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

现在按Container查询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)

这会导致对数据库进行两次SQL调用(实际上是4次调用,因为rails会为每个:include执行一次SQL

在一个SQL中无法执行此操作,因为您需要为不同的内容类型设置不同的列。

警告:不应直接使用Content类上的虚拟关联,因为它会导致意外结果。

E.g:假设contents表中的第一个对象包含食物。

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

第二次通话无效。它可能会为您提供一个Thing对象,其ID与Food指向的Content对象具有相同的ID。