10

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

例子:

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 就会出错,因为并非所有封闭的类型都有子模型到期。

4

1 回答 1

24

编辑后的答案

我最近发现,当您按多态类型列进行过滤时,Rails 支持预先加载多态关联。所以没有必要声明虚假的关联。

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

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

旧答案

这是一种 hack,因为没有直接的方法将多态对象包含在一个查询中。

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

现在查询Containerby 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 为每个调用一个 SQL :include

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

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

例如:假设contents表中的第一个对象包含食物。

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

第二次调用将不起作用。它可能会给你一个与 .指向的Thing对象具有相同 id 的对象。FoodContent

于 2010-03-05T22:56:16.627 回答