ActiveRecord,has_many:through和多态关联


117

民间,

想要确保我正确理解了这一点。并且请忽略此处继承的情况(SentientBeing),而尝试着眼于has_many:through关系中的多态模型。也就是说,请考虑以下事项...

class Widget < ActiveRecord::Base
  has_many :widget_groupings

  has_many :people, :through => :widget_groupings, :source => :person, :conditions => "widget_groupings.grouper_type = 'Person'"
  has_many :aliens, :through => :widget_groupings, :source => :alien, :conditions => "video_groupings.grouper_type = 'Alien'"
end

class Person < ActiveRecord::Base
  has_many :widget_groupings, :as => grouper
  has_many :widgets, :through => :widget_groupings
end

class Alien < ActiveRecord::Base
  has_many :widget_groupings, :as => grouper
  has_many :widgets, :through => :widget_groupings  
end

class WidgetGrouping < ActiveRecord::Base
  belongs_to :widget
  belongs_to :grouper, :polymorphic => true
end

在一个完美的世界中,我想给一个小部件和一个Person,执行以下操作:

widget.people << my_person

但是,当我这样做时,我注意到widget_groupings中“ grouper”的“ type”始终为null。但是,如果我执行以下操作:

widget.widget_groupings << WidgetGrouping.new({:widget => self, :person => my_person}) 

然后所有的工作都像我通常期望的那样。我认为我从未见过这种情况发生在非多态关联中,只是想知道这是否是该用例所特有的,或者我是否有可能盯着一个错误。

谢谢你的帮助!

Answers:


162

Rails 3.1.1的一个已知问题破坏了此功能。如果您首先遇到此问题,请尝试升级,此问题已在3.1.2中修复。

你好亲近 问题是您滥用了:source选项。:source应该指向多态的belongs_to关系。然后,您要做的就是为要定义的关系指定:source_type。

对Widget模型的此修复应允许您完全按照自己的意愿进行操作。

class Widget < ActiveRecord::Base
  has_many :widget_groupings

  has_many :people, :through => :widget_groupings, :source => :grouper, :source_type => 'Person'
  has_many :aliens, :through => :widget_groupings, :source => :grouper, :source_type => 'Alien'
end

哦,我的上帝,那是如此痛苦的显而易见,我简直不敢相信自己在其上釉。感谢EmFi!
Cory

没问题,我想我第一次遇到该问题时苦了一天。没有帮助,这是我在Rails中尝试做的不涉及遵循教程/书的第一件事。
EmFi

1
正如scotkf指出的那样,ActiveRecord 3.1.1中有一个回归阻止了此行为。升级到3.1.2将使该解决方案有效。
EmFi 2011年

6
和@Shtirlic提到的一样。有没有一种方法可以不指定source_type,所以您有混合的结果集?如果有人解决了这个问题,很想知道如何。
达蒙·奥

3
从Rails 4.2.0起仍然可以使用。但是,如果没有source_type和两个单独的关联,有什么方法可以完成这些工作?
Emeka

3

如上所述,由于:source上的错误,此方法不适用于rails 3.1.1,但已在Rails 3.1.2中修复。


-4

有很多:through和多态不能一起工作。如果尝试直接访问它们,则应该抛出错误。如果我没记错的话,您必须手写widget.people和推送例程。

我不认为这是一个错误,只是尚未实现的错误。我想我们会在功能中看到它,因为每个人都有可以使用它的情况。


6
他们确实在一起工作。例如:has_many:subscriptions,:as =>:subscribable has_many:subscribers,:through =>:subscriptions,:source =>:user
ScottJ

在不久的将来,我将把失败的代码的示例作为单独的帖子提出:)这将使我省去很多麻烦,以弄清楚如何绕过该错误。
cgr
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.