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