【问题标题】:Polymorphic has-many-through relationships in RailsRails 中的多态多通关系
【发布时间】:2016-03-07 01:14:13
【问题描述】:

我正在尝试与 ActiveRecord 建立多态多通关系。这是最终目标:

  • 用户可以属于多个组织和多个团队
  • 组织有很多用户和很多团队
  • 团队拥有许多用户并属于一个组织

我正在尝试使用 has-many-through 而不是 has-and-belongs-to-many,因为我需要将一些信息与关系(例如组织或团队中的用户角色)关联起来,所以我做了一个连接表Membership

我将如何实现这个?

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    我会这样设计架构:

    • Organization 有很多 Team
    • Team 有很多 TeamMember
    • User 有很多 TeamMember
    • TeamMember 属于 UserTeam

    模型将是:

    organization.rb

    class Organization < ActiveRecord::Base
      has_many :teams
      has_many :team_members, through: :teams
      has_many :users, through: :team_members
    end
    

    team.rb

    class Team < ActiveRecord::Base
      belongs_to :organization # fk: organization_id
      has_many :team_members
      has_many :users, through: :team_members
    end
    

    user.rb

    class User < ActiveRecord::Base
      has_many :team_members
      has_many :teams, through: :team_members
      has_many :organizations, though: :teams
    end
    

    team_member.rb

    class TeamMember < ActiveRecord::Base
      belongs_to :team      # fk: team_id
      belongs_to :user      # fk: user_id
      attr_accessible :role # role in team
    end
    

    因此,与您的要求进行比较:

    用户可以属于多个组织和多个团队

    => 好的

    组织有很多用户和很多团队

    => 好的

    团队有很多用户并且属于一个组织

    => 好的

    顺便说一句,我们这里没有使用任何多态,TeamMember 在你早期的想法中代表Membership

    【讨论】:

      【解决方案2】:

      对于多态关联,

      class User
        has_many :memberships
      end
      
      class Team
        belongs_to :organization
        has_many :memberships, :as => :membershipable #you decide the name
      end
      
      class Organization
        has_many :memberships, :as => :membershipable
        has_many :teams
      end
      
      class Membership
        belongs_to :user
        belongs_to :membershipable, polymorphic: true
      end
      

      请注意,UserTeamOrganization 间接关联,并且每个调用都必须经过Membership

      【讨论】:

        【解决方案3】:

        在我的项目中,我使用Relationship 类(在我命名为ActsAsRelatingTo 的gem 中)作为连接模型。它看起来像这样:

        # == Schema Information
        #
        # Table name: acts_as_relating_to_relationships
        #
        #  id                  :integer          not null, primary key
        #  owner_id            :integer
        #  owner_type          :string
        #  in_relation_to_id   :integer
        #  in_relation_to_type :string
        #  created_at          :datetime         not null
        #  updated_at          :datetime         not null
        #
        
        module ActsAsRelatingTo
          class Relationship < ActiveRecord::Base
        
              validates :owner_id,                  presence: true
              validates :owner_type,                presence: true
              validates :in_relation_to_id,         presence: true
              validates :in_relation_to_type,       presence: true
        
              belongs_to  :owner,                   polymorphic: true
              belongs_to  :in_relation_to,          polymorphic: true
        
          end
        end
        

        所以,在你的 User 模型中,你会说:

          class User < ActiveRecord::Base
        
            has_many :owned_relationships,
              as: :owner,
              class_name: "ActsAsRelatingTo::Relationship",
              dependent: :destroy
        
            has_many :organizations_i_relate_to, 
              through: :owned_relationships, 
              source: :in_relation_to, 
              source_type: "Organization"
        
            ...
        
          end
        

        我相信您可以不使用 source_type 参数,因为可以从 :organizations 推断出加入的类 (Organization)。通常,我加入的模型无法从关系名称中推断出类名,在这种情况下,我会包含 source_type 参数。

        有了这个,你可以说user.organizations_i_relate_to。您可以对任何一组类之间的关系进行相同的设置。

        你也可以在Organization 课堂上说:

        class Organization < ActiveRecord::Base
        
            has_many :referencing_relationships,
              as: :in_relation_to,
              class_name: "ActsAsRelatingTo::Relationship",
              dependent: :destroy
        
            has_many :users_that_relate_to_me, 
              through: :referencing_relationships, 
              source: :owner, 
              source_type: "User"
        

        所以你可以说organization.users_that_relate_to_me

        我厌倦了必须进行所有设置,因此在我的 gem 中我创建了一个 acts_as_relating_to 方法,以便我可以执行以下操作:

        class User < ActiveRecord::Base
          acts_as_relating_to :organizations, :teams
          ...
        end
        

        class Organization < ActiveRecord::Base
          acts_as_relating_to :users, :organizations
          ...
        end
        

        class Team < ActiveRecord::Base
          acts_as_relating_to :organizations, :users
          ...
        end
        

        所有的多态关联和方法都会“自动”为我设置好。

        抱歉,答案很长。希望你能从中找到有用的东西。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多