10

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

例子:

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中的过期,因为我知道我需要每一个人。有没有办法做到这一点?只是定义一个常规:包含错误,因为不是所有的封闭类型都有一个子模型到期。

回答

24

编辑答案

我最近发现Rails的支持多态关联的eager加载,当你在多态类型的列进行筛选。所以没有必要申报假关联。

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

现在,通过container_type查询Container

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_type查询Container

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调用铁轨执行一个SQL为每:include

没有办法,因为你需要不同的列来做到这一点在一个SQL为不同的内容类型设置。

警告:Content类的虚协会不能直接使用,因为它会导致意想不到的结果。

例如:可以说contents表中的第一个对象包含食物。

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

第二次调用不起作用。它可能会为您提供一个Thing对象,其ID为与Content指向的对象Food相同。

+0

我已根据一些新信息更新了我的答案,请看一看。 – 2010-10-12 01:32:00

+1

在何种版本的ActiveRecord中,多态关联的急切加载是否有效?它在3.2.3中不起作用 – nicholaides 2012-05-23 18:41:56

+0

@nicholaides它应该在3.2.3中工作。只有在按多态类型列进行筛选时才会发生热切加载。你遇到的错误是什么? – 2012-05-23 19:36:06