Already a month trying to solve the problem at first sight is not very complicated: There are 3 models - team, user and team_user (has_namy: through) In the form of edit and new team to do the ability to dynamically add members of this team.
Scenario:
- A user comes to the team new form
- Indicates the name of the team
- After name field select user (team member)
- Click the Add member button
- After validation of a member is added after team's name field in text field + delete button opposite
- From the selector delete his (member) name (as it is already a team member)
- In selite selects the next user, and click the Add member button
- Press the Submit button to save the new team and team's members
Difficulties:
- I tried to do through the gem Cocoon, but it is impossible to make different parshaly to select the user to be added to it (SELECT) and has added members (full name - text)
- If done through the <% = from_for ... remote: true%> and a separate controller or new action in the controller teams_controller, it will be two forms of nested (shape and form team team_user) with his 2nd submit button. Attachment forms, as I understand, is not gud.
- Changes in the form (changing the name of the team and add / remove the team members have the count only after clicking on the save to basically submit the form team)
app/models/user.rb
class User < ApplicationRecord
has_many :team_users
has_many :teams, through: :team_users
accepts_nested_attributes_for :team_users, :teams, allow_destroy: true
end
app/models/team.rb
class Team < ApplicationRecord
has_many :team_users
has_many :users, through: :team_users
accepts_nested_attributes_for :team_users, allow_destroy: true, reject_if: proc { |a| a['user_id'].blank? }
end
app/models/team_user.rb
class TeamUser < ApplicationRecord
belongs_to :team
belongs_to :user
accepts_nested_attributes_for :team, :user, allow_destroy: true
end
app/controllers/teams_controller.rb
class TeamsController < ApplicationController
before_action :set_team, :set_team_users, only: [:show, :edit, :update, :destroy]
before_action :set_team_ancestry, only: [:new, :edit, :create, :update, :destroy]
before_action :set_new_team_user, only: [:new, :edit]
before_action :logged_in_user
layout 'sidebar'
# GET /teams
def index
@teams = Team.search(params[:search], :name).sorting(params[:sort], params[:direction]).paginate(page: params[:page])
end
# GET /teams/1
def show
end
# GET /teams/new
def new
@team = Team.new(parent_id: params[:parent_id])
end
# GET /teams/1/edit
def edit
@team_users = @team.team_users
end
# POST /teams
def create
@team = Team.new(team_params)
respond_to do |format|
if @team.save
format.html { redirect_to @team, success: t('.flash.success.message') }
else
format.html { render :new, danger: t('.flash.danger.message') }
end
end
end
# PATCH/PUT /teams/1
def update
respond_to do |format|
if @team.update(team_params)
format.html { redirect_to @team, success: t('.flash.success.message') }
else
format.html { render :edit, danger: t('.flash.danger.message') }
end
end
end
# DELETE /teams/1
def destroy
@team.destroy
respond_to do |format|
format.html { redirect_to teams_url, success: t('.flash.success.message') }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_team
@team = Team.find(params[:id])
end
def set_team_ancestry
@team_collection = Team.where.not(id: params[:id]).all.each { |c| c.ancestry = c.ancestry.to_s + (c.ancestry != nil ? "/" : '') + c.id.to_s
}.sort{ |x,y| x.ancestry <=> y.ancestry }.map{ |c| ["-" * (c.depth - 1) + c.name,c.id] }
end
def set_team_users
@team_users_collection = User.all.collect { |p| [ p.name, p.id ] }
end
def set_new_team_user
@team_users_new = @team.team_users.build
end
# Never trust parameters from the scary internet, only allow the white list through.
def team_params
params.require(:team).permit(
:name,
:parent_id,
team_users_attributes: [:_destroy, :id, :user_id]
)
end
end