Here are my 3 models.
User
has_many :memberships
has_many :teams, through: :memberships, dependent: :destroy
accepts_nested_attributes_for :memberships
Team
has_many :memberships
has_many :users, through: :memberships, dependent: :destroy
accepts_nested_attributes_for :memberships
Membership
belongs_to :team
belongs_to :user
Here are some portions of my Team controller. My objective here is to add/update members to a certain team. Note that the source for adding members already exists as a group of users.
TeamsController
def create
@team = Team.new(team_params)
@team.users << User.find(member_ids) #add leader and members to team
if @team.save
#redirect to created team
else
#show errors
end
end
def update
#TO DO: update team roster here
if @team.update(team_params)
#redirect to updated team
else
#show errors
end
end
Strong parameters for Team controller
#parameters for team details
def team_params
params.require(:team).permit(:name, :department)
end
#parameters for members (includes leader)
def members_params
params.require(:team).permit(:leader, members:[])
end
#get id values from members_params and store in an array
def member_ids
members_params.values.flatten
end
For the form, I only have:
- Name (text field)
- Department (combo box)
- Leader (combo box, with options generated depending on the selected department, submits as a selected user's user id)
- Members (combo box, multiple, with options generated depending on the selected department, submits as an array of selected users' user ids)
I can successfully create a team, together with the passing of validations (both team and membership model), on my create. However, I have no idea on how to update the team, because if I use @team.users.clear
and then simply do the same thing from create (I know, it's a bit stupid to do this), it will validate, but it will save it regardless if there's an error or not.
FORM CODE
<%= form_for(@team, remote: true) do |f| %>
<%= f.label :name, "Name" %>
<%= f.text_field :name %>
<%= f.label :department, "Department" %>
<%= f.select :department, options_for_select(["Architectural", "Interior Design"], department), include_blank: true %>
<%= f.label :leader, "Leader" %>
<%= f.select :leader, select_leaders(department, @team.id), {include_blank: true, selected: pre_select(:leader)} %>
<%= f.label :members, "Members" %>
<%= f.select :members, select_members(department, @team.id), {include_blank: true}, {id: "team_members", multiple: :multiple, data: {member_ids: pre_select(:members)}}%>
<% end %>
Note for the form:
- This form works for both blank and populated forms.
- The
:members
field is select2 enabled.
So my questions here are:
- How can I update members of team? Is it possible to update based from what my strong parameters currently have, or do they need to be revised?
- Should my create method be revised too?
SOME OPTIONS LEADING TO SOLUTION
Option #1 (best solution so far)
I only did a first-aid solution for this, so I think there's a better approach than what I did below. What I did here is to create users params with the users found from the member_ids as values.
TeamsController
def create
team = Team.new(team_params.merge({users: User.find(member_ids)}))
...
end
def update
...
if @team.update(team_params.merge({users: User.find(member_ids)}))
..
end
Option #2
Independent from solution 1, I only had team_params
as strong parameter.
TeamsController
...
private
def team_params
params.require(:team).permit(:name, :department, :leader, members:[])
end
I created setter methods for both leader and members. But it seems that members overwrites the leader setter because I used the update
method for both setters, and the update uses the same resource which is users. A workaround seems to be possible with this option.
Team
...
def leader=(leader_id)
#self.update(users: User.find(leader_id))
end
def members=(members_ids)
#self.update(users: User.find(members_id))
end