I believe what you're looking for is a join table model. The issue is that both a User
and a Team
may have many of each other. So the relationship must be stored separately.
See this answer here on a similar question: https://stackoverflow.com/a/15442583/5113832
So you might choose a model structure of User
, Team
and TeamMembership
.
Updated to destroy dependent team memberships when a user or team is destroyed.
#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
Updated to reply to question:
How would my controller look on create? (Adding a user to a team) – Michael
In order to add a user to to a team you COULD do it in UserController
, you COULD do it in TeamController
. However, because you are now creating a TeamMembership
resource you would want to create a TeamMembership
record in a TeamMembershipsController
. This keeps with the "Rails" way of doing things. So for example:
# 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
The advantage to having the TeamMembership
resource is using this pattern to manage when a user is added (#create), or removed (#destroy) from a team.
The magic of Rails associations will take care of accessing a team's members (users) and a user's teams for each instance of those models.
You just go about your business doing CRUD on these resources and Rails takes care of the organization for you by your conforming to it's conventions.
Also I updated my original model code to destroy team memberships when a user or team is destroyed. This ensures no orphaned records are in your team_memberships
table.
As a final note. You should also be able to easily use form_for
to send a TeamMembership
to your controller to be created. This could be done using select option dropdowns for users and teams with 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 %>
The above code will render dropdown for all users and teams allowing you to select a specific combination to create a team membership from. Deleting a team membership is as easy as sending a DELETE #destroy
request with the id
of the team membership.
Another consideration might be adding a unique pair constraint to your database table and model within the migration and model validations.
Hope this helps!