我不知道如何创建它,我想创建一个多对多的多态关联。
我有kjh
模型,属于question
。
现在问题可以是company
,has_many users
或groups
。取决于您如何分配它。
我希望能够将问题分配给一个/多个用户,或一个/多个组,或者它所属的公司。
我该如何设置呢?
答案 0 :(得分:3)
在这种情况下,我会添加一个Assignment模型,它充当问题与分配给它的实体之间的交集。
让我们运行一个生成器来创建所需的文件:
rails g model assignment question:belongs_to assignee_id:integer assignee_type:string
然后,让我们打开创建的迁移文件(db/migrations/...__create_assignments.rb)
:
class CreateAssignments < ActiveRecord::Migration
def change
create_table :assignments do |t|
t.integer :assignee_id
t.string :assignee_type
t.belongs_to :question, index: true, foreign_key: true
t.index [:assignee_id, :assignee_type]
t.timestamps null: false
end
end
end
如果您在此处注意,可以看到我们为question_id
但不是assignee_id
添加了外键。这是因为数据库不知道哪个表assignee_id
指向并且不能强制引用完整性*。我们还为[:assignee_id, :assignee_type]
添加了一个复合索引,因为它们总是会被一起查询。
class Assignment < ActiveRecord::Base
belongs_to :question
belongs_to :assignee, polymorphic: true
end
polymorpic: true
选项告诉ActiveRecord查看assignee_type
列,以决定从中加载assignee
的表。
class User < ActiveRecord::Base
has_many :assignments, as: :assignee
has_many :questions, through: :assignments
end
class Group < ActiveRecord::Base
has_many :assignments, as: :assignee
has_many :questions, through: :assignments
end
class Company < ActiveRecord::Base
has_many :assignments, as: :assignee
has_many :questions, through: :assignments
end
不幸的是,多态关系的一个警告是你不能急于加载多态的受让人关系。或者声明has_many :assignees, though: :assignments
。
一种解决方法是:
class Group < ActiveRecord::Base
has_many :assignments, as: :assignee
has_many :questions, through: :assignments
def assignees
assignments.map(&:assignee)
end
end
但这会导致效率非常低的SQL查询,因为每个受理人都会被加载到查询中!
相反,你可以这样做:
class Question < ActiveRecord::Base
has_many :assignments
# creates a relationship for each assignee type
['Company', 'Group', 'User'].each do |type|
has_many "#{type.downcase}_assignees".to_sym,
through: :assignments,
source: :assignee,
source_type: type
end
def assignees
(company_assignees + group_assignees + user_assignees)
end
end
每个受让人类型只会导致一次查询,这是一个很大的改进。