多对多的多态关联

我不知道如何创建它,我想创建一个多对多的多态关联。

我有一个question模型,属于一家company

现在问题可能是has_many usersgroupscompany 。 取决于您如何分配它。

我希望能够将问题分配给一个/多个用户,或一个/多个组,或者它所属的公司。

我该怎么做呢?

在这种情况下,我会添加一个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 

这对每个受让人类型只会导致一个查询,这是一个很大的改进。