質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.10%

多対多(TeamとUser)のTeam作成・編集フォームで、Userを重複登録できないようにしたい。

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 234

yamamoto11081

score 16

前提・実現したいこと

Team作成・編集フォームで、Teamに所属するUserを検索し追加できるようにしたいです。
検索はUserの名前を入力し、ajaxで通信するようにしています。

発生している問題・エラーメッセージ

Userを検索しTeamのメンバーに追加、中間テーブルに保存することはできるのですが、
すでにメンバーになっているUserもずっと検索できてしまうので、検索結果に出てこないようにしたいです。

該当のソースコード

team.rb

class Team < ApplicationRecord
  has_many :team_users
  has_many :users, through: :team_users
end
team_user.rb

class TeamUser < ApplicationRecord
  belongs_to :team
  belongs_to :user
end
user.rb

class User < ApplicationRecord
  has_many :team_users
  has_many :teams, through: :team_users
end
teams_controller.rb

class TeamsController < ApplicationController
  before_action :set_team, except: [:new, :create]

  def show
  end

  def new
    @team = Team.new
    @team.users << current_user
    @users = @team.users.where.not(id: current_user.id)
  end

  def create
    @team = Team.new(team_params)
    if @team.save
      redirect_to team_path(@team)
    else
      render :new
    end
  end

  def edit
    @users = @team.users.where.not(id: current_user.id)
  end

  def update
    if @team.update(team_params)
      redirect_to team_path(@team)
    else
      render :edit
    end
  end

  def destroy
  end

  private

  def team_params
    params.require(:team).permit(:name, :about, :image, user_ids: [])
  end

  def set_team
    @team = Team.find(params[:id])
  end
end
member_search.js

$(function() {
  $(document).on('turbolinks:load', function() {
    function appendUser(user) {
      var html = `<div class="member__search__result__list">
                    <div class="user__name">${user.name}</div>
                    <div class="member__add btn btn-outline-primary btn-sm">追加</div>
                  </div>`
      $('#member__search__result').append(html);
    }
    function appendMember(user) {
      var html = `<div class="team__member">
                    <input name='team[user_ids][]' type='hidden' value='${user.id}'>
                    <div class="user__name">${user.name}</div>
                    <div class="member__delete btn btn-outline-danger btn-sm">削除</div>
                  </div>`
      $('#team__members').append(html);
    }
    function appendErrMsg(msg) {
      var html = `<div>${msg}</div>`
      $('#member__search__result').append(html);
    }
    // ユーザー検索
    $('#member__search').on('click', function() {
      var input = $('#member__search__field').val();
      $.ajax({
        type: 'GET',
        url: '/users',
        data: {keyword: input},
        dataType: 'json'
      })
      .done(function(users) {
        $('#member__search__result').empty();
        if (users.length !== 0) {
          users.forEach(function(user) {
            appendUser(user); // 検索結果を表示
            $('.member__search__result__list').on('click', '.member__add', function() {
              appendMember(user); //追加ボタンでチームメンバーに追加
              $(this).parent().remove();
            })
          });
        }
        else {
          appendErrMsg("ユーザーが見つかりません");
        }
      })
      .fail(function() {
        alert('ユーザーを検索できませんでした');
      })
    })
    $("#team__members").on("click", ".member__delete", function() {
      $(this).parent().remove(); //削除ボタンでチームメンバーから削除
    });
  });
});
users_controller.rb

class UsersController < ApplicationController

  def index
    @users = User.where(name: (params[:keyword])).where.not(id: current_user.id)
    respond_to do |format|
      format.html
      format.json
    end
  end
end
users/index.json.jbuilder

json.array! @users do |user|
  json.id user.id
  json.name user.name
end
_team_form.html.haml

.board__form
  = form_for @team do |f|
    - if @team.errors.any?
      .form__errors
        %h3= "#{@team.errors.full_messages.count}件のエラーが発生しました。"
        %ul
          - @team.errors.full_messages.each do |message|
            %li= message
    .form-group
      = f.label :name, class: 'form-control-label'
      %br/
      = f.text_field :name, class: 'form-control'
    .form-group
      = f.label :about, class: 'form-control-label'
      %br/
      = f.text_area :about, class: 'form-control'
    .form-group
      = f.label :image, class: 'form-control-label'
      %br/
      = f.file_field :image
    .form-group
      %label Add member
      %br/
      %input#member__search__field{placeholder: 'ユーザー名を入力', type: 'text', name: 'keyword'}
      %button{type: "button", class: "btn btn-outline-success btn-sm",id: "member__search"} Search
      #member__search__result
      -# 検索結果を表示

      #team__members
        [Team Members]
        .team__member
          %input{name: "team[user_ids][]", type: "hidden", value: current_user.id}
          %p.user__name
            = current_user.name

        - if @users.present?
          - @users.each do |user|
            .team__member
              %input{name: "team[user_ids][]", type: "hidden", value: user.id}
              %p.user__name
                = user.name
              %button{class: "member__delete btn btn-outline-danger btn-sm"} 削除
    .form-group
      = f.submit "Save", class: "btn btn-primary"

補足情報(FW/ツールのバージョンなど)

Ruby 2.6.3
Rails 5.2.3

チームフォーム

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

DBに強い方からはもっとかっこ良いのがいただけるかとは思いますが、

Userを検索するときに
where.not(id: @team.users.map(&:id))

で絞り込んではどうでしょう

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる