1

Rails/ActiveRecord とのポリモーフィックな has_and_belongs_to_many 関係を作成するにはどうすればよいですか?

私が目にするほとんどの例は、1 つの親のみに関連するポリモーフィック側を制限する属している関係を作成することを含みます。

表: タスク

表: Tasks_Targets

表: CustomerStore

表: ソフトウェアシステム

この状況では、CustomerStore と SoftwareSystem の両方が「Targetable」タイプになります。私が理解していることから、ほとんどの例が示すようにポリモーフィックな関係を実装すると、Targetable を Taskに一度しか関連付けることができません。

ほとんどのオンライン検索では、この関係の背後にある理論の一部がまだ説明されていないため、いくつかの明確化が役立つ場合があります...

ありがとう!

4

2 に答える 2

6

ドメインの説明を踏まえて、問題を解決する方法の小さなテスト主導の例を作成しました。ドメインの不一致が見られた場合は、お気軽にさらに明確にしてください (私はacts_as_fu gemテスト モデルをその場で作成するために my を使用しています)。

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
于 2009-07-14T05:23:32.857 に答える