【问题标题】:Rails 4 self referential many to many relationshipsRails 4自引用多对多关系
【发布时间】:2015-12-03 23:23:45
【问题描述】:

我无法解决这个问题,任何帮助将不胜感激。我在这里浏览了许多文章和其他帖子,但似乎无法获得我正在寻找的结果。

我有一个用户模型和一个团队模型。

团队模型有 user_id 和 team_id

创建团队的用户将是 user_id,而作为团队成员的用户将在 team_id 中

User Model
 has_many :teams, foreign_key: :team_id
 has_many :team_members, class_name: "Team", foreign_key: :user_id

Team Model
 belongs_to :user, foreign_key: :team_id    
 belongs_to :team_member, class_name: "User", foreign_key: :user_id

我想要达到的最终结果是:

  • 每个用户可以添加尽可能多的团队成员
  • 每个用户都可以看到属于其团队的用户列表。
  • 一个视图,属于团队的用户可以查看他们属于哪个团队。

【问题讨论】:

  • 我怀疑您想要has_and_belongs_to_many 关系,但您想要做什么并不完全清楚。
  • @Undo 感谢您的评论。我对此进行了调查,但无法使其正常工作。你能告诉我一个例子,我将如何在上面的模型中使用它吗?

标签: ruby-on-rails ruby ruby-on-rails-4


【解决方案1】:

我相信您正在寻找的是join table model。问题是User 和Team 可能有很多彼此。所以关系必须单独存储。

在此处查看类似问题的答案:https://stackoverflow.com/a/15442583/5113832

所以你可以选择User、Team和TeamMembership的模型结构。

更新以在用户或团队被销毁时销毁相关团队成员资格。

#app/models/user.rb
class User < ActiveRecord::Base
  has_many :team_memberships, :dependent => :destroy
  has_many :teams, :through => :team_memberships
end

#app/models/team.rb
class Team < ActiveRecord::Base
  has_many :team_memberships, :dependent => :destroy
  has_many :users, :through => :team_memberships
end

#app/models/team_membership.rb
class TeamMembership < ActiveRecord::Base
  belongs_to :user
  belongs_to :team
end

更新以回复问题:

我的控制器在创建时的外观如何? (将用户添加到团队中)– Michael

要将用户添加到您可以在UserController 中执行的团队,您可以在TeamController 中执行此操作。但是,由于您现在正在创建 TeamMembership 资源,因此您可能希望在 TeamMembershipsController 中创建 TeamMembership 记录。这与“Rails”的做事方式保持一致。比如:

# app/controllers/team_memberships_controller.rb
class TeamMembershipsController < ApplicationController
  def index
    @team_memberships = TeamMembership.all
  end

  def new
    @team_membership = TeamMembership.new
  end

  def create
    @team_membership = TeamMembership.new(team_membership_params)
    if @team_membership.save
      flash[:success] = 'Team membership created'
      redirect_to team_memberships_path
    else
      flash[:error] = 'Team membership not created'
      render :new
    end
  end

  def destroy
    @team_membership = TeamMembership.find_by_id(params[:id])
    if @team_membership && @team_membership.destroy
      flash[:success] = 'Team membership destroyed'
    else
      flash[:error] = 'Team membership not destroyed'
    end
    redirect_to team_memberships_path
  end


  private
  def team_membership_params
    params.require(:team_membership).permit(
      :user_id,
      :team_id
    )
  end
end

拥有TeamMembership 资源的优势在于使用此模式来管理何时从团队中添加(#create)或删除(#destroy)用户。

Rails 的魔力associations 将负责访问团队成员(用户)以及这些模型的每个实例的用户团队。

您只需在这些资源上通过CRUD 开展业务,Rails 会通过您遵守其约定来为您处理组织。

我还更新了我的原始模型代码,以在用户或团队被破坏时破坏团队成员资格。这可确保您的 team_memberships 表中没有 orphaned records。

作为最后一点。您还应该能够轻松地使用form_for 将TeamMembership 发送到要创建的控制器。这可以通过 Rails 的collection_select 为用户和团队使用选择选项下拉列表来完成:

<%# app/views/team_memberships/new.html.erb %>
<h1>
  Create Team Membership
</h1>

<%= form_for(@team_membership) do |f| %>
  <%= f.label(:user) %>
  <%= f.collection_select(
    :user_id,
    User.all,
    :id,
    :username
  ) %>

  <%= f.label(:team) %>
  <%= f.collection_select(
    :team_id,
    Team.all,
    :id,
    :name
  ) %>

  <%= f.submit %>
<% end %>

以上代码将为所有用户和团队呈现下拉菜单,让您可以选择特定组合来创建团队成员资格。删除团队成员就像发送 DELETE #destroy 请求和团队成员的 id 一样简单。

另一个考虑因素可能是在迁移和模型验证中将unique pair constraint 添加到您的数据库表和模型中。

希望这会有所帮助!

【讨论】:

  • 谢谢,这是有道理的!我的控制器在创建时会如何? (将用户添加到团队)
  • 如果您有一个像user = User.first 这样的用户和一个团队team = Team.first,您可以使用team.users &lt;&lt; user 和调用team.save 将用户添加到团队中
  • @Michael 我更新了我的答案,以举例说明 TeamMembershipsController 的外观以及一些视图、表单和提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-19
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多