Ale*_*zzi 33 ruby-on-rails polymorphic-associations
查看评论以获取更新.
我一直在努力在这个问题上得到明确而直截了当的答案,我希望这次我能得到它!:D我肯定还有很多东西需要学习Rails,但我确实理解我面临的问题,并且非常感谢额外的帮助.
因此,我认为任务与子目标的子类之间的多对多关系是有序的.更详细地说,我将能够在控制台(当然还有其他地方)做这样的事情:
task = Task.find(1)
task.targets
[...array of all the subclasses of Target here...]
Run Code Online (Sandbox Code Playgroud)
但!假设存在"存储","软件","办公室","车辆"等模型,它们都是"目标"的子类,那么在另一个方向上遍历关系也会很好:
store = Store.find(1)
store.tasks
[...array of all the Tasks this Store is related to...]
software = Software.find(18)
software.tasks
[...array of all the Tasks this Software is related to...]
Run Code Online (Sandbox Code Playgroud)
多态关系隐含的数据库表似乎能够进行这种遍历,但我在尝试寻找一个能够打败多态关系精神的答案时看到一些反复出现的主题:
它似乎是导轨功能或集体社区知识中的一个小漏洞.所以希望stackoverflow可以记录我的搜索答案!
感谢所有帮助的人!
SFE*_*ley 56
您可以结合使用多态并has_many :through获得灵活的映射:
class Assignment < ActiveRecord::Base
belongs_to :task
belongs_to :target, :polymorphic => true
end
class Task < ActiveRecord::Base
has_many :targets, :through => :assignment
end
class Store < ActiveRecord::Base
has_many :tasks, :through => :assignment, :as => :target
end
class Vehicle < ActiveRecord::Base
has_many :tasks, :through => :assignment, :as => :target
end
Run Code Online (Sandbox Code Playgroud)
......等等.
Rap*_*oni 12
尽管SFEley提出的答案很好,但存在一些缺陷:
考虑到这一点,我最简单的解决方案是:
class Assignment < ActiveRecord::Base
belongs_to :task
belongs_to :target, :polymorphic => true
end
class Task < ActiveRecord::Base
has_many :assignments
# acts as the the 'has_many targets' needed
def targets
assignments.map {|x| x.target}
end
end
class Store < ActiveRecord::Base
has_many :assignments, as: :target
has_many :tasks, :through => :assignment
end
class Vehicle < ActiveRecord::Base
has_many :assignments, as: :target
has_many :tasks, :through => :assignment, :as => :target
end
Run Code Online (Sandbox Code Playgroud)
参考文献:http: //blog.hasmanythrough.com/2006/4/3/polymorphic-through
这可能不是一个特别有用的答案,但简单地说,我认为没有一种简单或自动的方法可以做到这一点。至少,不像更简单的一对一或多对多关联那么容易。
我认为为连接表创建 ActiveRecord 模型是解决该问题的正确方法。正常has_and_belongs_to_many关系假设两个指定表之间存在联接,而在您的情况下,听起来您想要在 、 、 或 中的任何一个之间联接(顺便说tasks一句,是否有理由不在这里使用 STI?看起来像通过限制您拥有的表的数量来帮助降低复杂性)。因此,在您的情况下,连接表还需要知道所涉及的子类的名称。就像是storessoftwaresofficesvehiclesTarget
create_table :targets_tasks do |t|
t.integer :target_id
t.string :target_type
t.integer :task_id
end
Run Code Online (Sandbox Code Playgroud)
然后,在您的Task类、Target子类和类中,您可以使用ActiveRecord::Associations::ClassMethods rdoc 页上记录的关键字来TargetsTask设置关联。has_many:through
但是,这仍然只能帮助您完成部分任务,因为:through您不知道如何使用该target_type字段作为Target子类名称。为此,您也许可以编写一些自定义 select/finder SQL 片段,这些片段也记录在ActiveRecord::Associations::ClassMethods中。
希望这能让您朝着正确的方向前进。如果您找到完整的解决方案,我很乐意看到它!