【问题标题】:many to many polymorphic association多对多多态关联
【发布时间】:2015-10-12 09:33:00
【问题描述】:

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

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

现在问题可以has_many usersgroupscompany。取决于你如何分配它。

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

我该如何进行设置?

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    在这种情况下,我将添加一个分配模型,它充当问题和分配给它的实体之间的交集。

    创建表

    让我们运行一个生成器来创建所需的文件:

    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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-06
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多