多态habtm与Rails/ActiveRecord的关系
问题描述:
我将如何去创建一个多态has_and_belongs_to_many与Rails/ActiveRecord的关系?多态habtm与Rails/ActiveRecord的关系
多数时候我看到涉及创建这限制了我的多态,一边被相关只有一个父一个belongs_to的关系的实例:
表:任务
表:Tasks_Targets
表:CustomerStore
表:SoftwareSystem
CustomerStore和SoftwareSystem都是ty pe在这种情况下是“目标”。根据我的理解,如果我通过大多数示例显示实现多态关系,我只能将目标与任务关联一次。
一些澄清可能有助于大多数在线搜索仍然留下一些背后的关系不明原因的理论......
谢谢!
答
鉴于你对域名的解释,我提出了一个小测试驱动的例子,说明如何解决你的问题。如果您发现任何域名不一致的情况,请随时进一步澄清(我正在使用我的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
答
为了配合中岛与问候回答您的问题,这是我会怎么做:
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
。
这看起来不错!我唯一担心的是我坚持在“任务”中定义每个“可定位”。有没有办法解决这个问题? Task.targets/targetables呢? – 2009-07-14 13:25:49