🐱

Rails グループへの参加/退会

2023/05/04に公開

この続きです🏋🏻
https://zenn.dev/goldsaya/articles/f32a3b3186084f

要件

  • 自分がグループオーナーでない場合は、グループ詳細画面に「Join this group」ボタンを表示させる
  • 「Join this group」ボタンをクリックすると、グループに参加。
    グループ一覧画面にメンバーの人数とグループ詳細画面のリストに参加したユーザとして表示される
  • 参加中のグループの場合は「Leave this group」でグループから抜けられる

完成

グループ一覧画面

グループ詳細画面

モデルの記述

group.rb
has_many :users, through: :group_users, source: :user

def includesUser?(user)
  group_users.exists?(user_id: user.id)
end

has_many :users, through: :group_users, source: :user
Group モデルが GroupUser モデルを通じて User モデルと関連していることを表す。

includesUser?(user)は、与えられたuserがグループのメンバーであるかどうかを判定するメソッドを記述。
group_usersテーブルから、user_idがuserのidと一致するレコードが存在するかどうかをチェック。存在する場合はtrueを、存在しない場合はfalseを返す!

ルーティングの記述

routes.rb
resources :groups, only:  [:new, :index, :show, :create, :edit, :update] do
    resource :group_users, only: [:create, :destroy]
  end

group_idがあればOKなので、resourceでネストさせる。
以下のルーティングが追加された!

コントローラーの記述

rails g controller group_users

group_users_controller.rb
class GroupUsersController < ApplicationController
  before_action :authenticate_user!
  
  def create #①
    group_user = current_user.group_users.new(group_id: params[:group_id])
    group_user.save
    redirect_to request.referer
  end
  
  def destroy #②
    group_user = current_user.group_users.find_by(group_id: params[:group_id])
    group_user.destroy
    redirect_to request.referer
  end
end

〜解説〜
①create
グループに参加するために、group_usersという中間テーブルにユーザーとグループの関連を作成するcreateアクション。
current_userを使用して、現在のユーザーを取得し、group_usersに.newメソッドで新しいレコードを作成。その際、group_idを渡して、どのグループに参加するかを指定している!
group_userオブジェクトを保存し、redirect_to request.refererで前にいたページに戻る。

②destroy
現在ログインしているユーザーが所属しているグループから退会するためのdestroyアクション。
ログインしているユーザーの group_users 関連付けを使用して、指定されたグループに関連付けられた group_userインスタンスをfind_byメソッドで検索。
destroy メソッドを使用して、 group_userを削除し、redirect_to request.refererで前にいたページに戻る。

ビューの記述

メンバー数を表示させる。

groups/_index.html.erb
<%= group.group_users.count %>

ここで、グループ作成者も最初からメンバーに含むようにしたかったのですが、うまく実装できず、、
とりあえず要件にはないので、このまま行きます😣

参加中のメンバーを表示させる。

groups/show.html.erb
<% @group.users.each do |user| %>
  <li style="list-style: none;"><%= user.name %></li>
<% end %>

@groupに参加している全てのユーザーの名前をリスト形式で表示。
usersという関連付けがあるため、@group.usersでグループに参加している全てのユーザーが取得でき、eachメソッドを用いて1つずつ処理しながら、その名前を表示している。

参加・退会ボタンを表示する。

表示させたいところへ以下の記述を追加!

groups/show.html.erb
<% if @group.is_owned_by?(current_user) %>
  <%= link_to 'Edit', edit_group_path(@group), class: "btn btn-sm btn-success" %>
<% elsif @group.includesUser?(current_user)%>
  <%= link_to 'Leave this group', group_group_users_path(@group), method: :delete, class: "btn btn-sm btn-danger" %>
<% else %>
  <%= link_to 'Join this group', group_group_users_path(@group), method: :post, class: "btn btn-sm btn-success" %>
<% end %>

〜解説〜
@group.is_owned_by?(current_user)
ログインしているユーザーがそのグループのオーナーかどうかを判定

@group.includesUser?(current_user)
ログインしているユーザーがそのグループのメンバーかどうかを判定

これらの条件分岐を元に、以下のように表示を分けている!

ログインしているユーザーがそのグループのオーナーの場合、グループ情報を編集するための「Edit」ボタンを表示。

ログインしているユーザーがそのグループのメンバーの場合、グループから退会するための「Leave this group」ボタンを表示。

ログインしているユーザーがそのグループのメンバーでもオーナーでもない場合、グループに参加するための「Join this group」ボタンを表示。


この流れで実装できるはずです。
何か間違いなどあればぜひ教えていただけますと幸いです!

🌱参考にさせていただいた記事
https://qiita.com/ki_87/items/eb2d073c2dccbed42c5a

Discussion