多对多的多态关联
我不知道如何创建它,我想创建一个多对多的多态关联。
我有一个question
模型,属于一家company
。
现在问题可能是has_many users
, groups
或company
。 取决于您如何分配它。
我希望能够将问题分配给一个/多个用户,或一个/多个组,或者它所属的公司。
我该怎么做呢?
在这种情况下,我会添加一个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
这对每个受让人类型只会导致一个查询,这是一个很大的改进。