与Rails / ActiveRecord的多态habtm关系

我将如何创建与Rails / ActiveRecord的多态has_and_belongs_to_many关系?

我看到的大多数示例都涉及创建belongs_to关系,该关系将我的多态性限制为仅与一个父级相关:

表:任务

表:Tasks_Targets

表:CustomerStore

表:SoftwareSystem

在这种情况下,CustomerStore和SoftwareSystem都将属于“Targetable”类型。 根据我的理解,如果我实现大多数示例所示的多态关系,我只能将Targetable与任务关联一次

一些澄清可能有所帮助,因为大多数在线搜索仍然留下这种关系背后的一些理论无法解释……

谢谢!

鉴于您对域名的解释,我已经提出了一个小型的测试驱动示例,说明如何解决您的问题。 如果您发现任何域名不一致,请随时进一步澄清(我正在使用我的acts_as_fu gem来动态启动测试模型)。

 require 'acts_as_fu' # class Task < ActiveRecord::Base build_model(:tasks) do integer :task_target_id has_many :task_targets has_many :customer_stores, :through => :task_targets, :source => :targetable, :source_type => 'CustomerStore' has_many :software_systems, :through => :task_targets, :source => :targetable, :source_type => 'SoftwareSystem' end # class TaskTarget < ActiveRecord::Base build_model(:task_targets) do string :targetable_type integer :targetable_id integer :task_id belongs_to :targetable, :polymorphic => true belongs_to :task end # class CustomerStore < ActiveRecord::Base build_model(:customer_stores) do has_many :task_targets, :as => :targetable has_many :tasks, :through => :task_targets end # class SoftwareSystem < ActiveRecord::Base build_model(:software_systems) do has_many :task_targets, :as => :targetable has_many :tasks, :through => :task_targets end require 'test/unit' class PolymorphicDomainTest < Test::Unit::TestCase # Test that customer stores can have multiple tasks def test_customer_store_gets_task task = Task.create! customer_store = CustomerStore.create! customer_store.task_targets.create! :task => task assert customer_store.tasks.include?(task) end def test_many_customer_stores_get_task task_a = Task.create! task_b = Task.create! customer_store = CustomerStore.create! :tasks => [task_a, task_b] assert customer_store.tasks.include?(task_a) assert customer_store.tasks.include?(task_b) end # Test that software systems can have multiple tasks def test_software_system_gets_task task = Task.create! software_system = SoftwareSystem.create! software_system.task_targets.create! :task => task assert software_system.tasks.include?(task) end def test_many_software_systems_get_task task_a = Task.create! task_b = Task.create! software_system = SoftwareSystem.create! :tasks => [task_a, task_b] assert software_system.tasks.include?(task_a) assert software_system.tasks.include?(task_b) end # Test that Tasks can have multiple customer stores def test_task_has_many_customer_stores task = Task.create! customer_store_a = CustomerStore.create! customer_store_b = CustomerStore.create! task.customer_stores = [customer_store_a, customer_store_b] task.save! task.reload assert task.customer_stores.include?(customer_store_a) assert task.customer_stores.include?(customer_store_b) end # Test that Tasks can have multiple software systems def test_task_has_many_software_systems task = Task.create! software_system_a = SoftwareSystem.create! software_system_b = SoftwareSystem.create! task.software_systems = [software_system_a, software_system_b] task.save! task.reload assert task.software_systems.include?(software_system_a) assert task.software_systems.include?(software_system_b) end end 

为了补充nakajima关于你的关注的答案,这是我将如何做到的:

 class Task < ActiveRecord::Base def targets # Get Array of all targetables tt = TaskTarget.select_all("SELECT targetable_type, targetable_id FROM task_targerts WHERE task_id = #{self[:id]}") # Build Hash of targetable_type => Array of targetable_ids targetables = Hash.new { |hash, key| hash[key] = [] } tt.each do |targetable| targetables[targetable.targetable_type] << targetable.targetable_id end # Query each "targetable" table once and merge all results targetables.keys.map{|key| (eval key).find(targetables[key])}.flatten end end 

确保在task_id表中索引task_targets