1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】グループ機能の実装手順

Last updated at Posted at 2024-09-14

この記事では、Railsでグループオーナーが作成したグループに、ユーザーがグループに参加・離脱できるようなグループ作成機能を実装する方法をまとめています。

作製するモデルのアソシエーション

今回作成するテーブルはGroupUserGroupのふたつです。

スクリーンショット 2024-09-14 204259.png

Groupテーブル

グループの情報を保存します(nameintroductionimage_idなど)。
owner_idフィールドにより、グループの所有者(ユーザー)を表します。

GroupUserテーブル

中間テーブルで、ユーザーがどのグループに所属しているかを管理します。
user_idgroup_idUserGroupを関連付けています。

実装手順

1. GroupモデルとGroupUserモデルの作成

まず、Groupモデルと、グループに所属するユーザーを管理するGroupUserモデルを作成します。
rails generate model Group name:string introduction:text image_id:string owner_id:integer

group_usersテーブルのマイグレーション
class CreateGroupUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :group_users do |t|
      t.integer :user_id
      t.integer :group_id

      t.timestamps
    end
  end
end

rails generate model GroupUser user:references group:references

groupsテーブルのマイグレーション
class CreateGroups < ActiveRecord::Migration[6.0]
  def change
    create_table :groups do |t|
      t.string :name
      t.text :introduction
      t.integer :owner_id

      t.timestamps
    end
  end
end

2. アソシエーションとバリデーションの追加

次に、Userモデル、Groupモデル、GroupUserモデルにアソシエーションとバリデーションを追加します。

user.rb
class User < ApplicationRecord
  has_many :group_users, dependent: :destroy
  has_many :groups, through: :group_users # user.groupsが利用可能に
end
group_user.rb
class GroupUser < ApplicationRecord
  belongs_to :user
  belongs_to :group

  validates_uniqueness_of :group_id, scope: :user_id # 同じユーザーが同じグループに複数回参加しないように
end
group.rb
class Group < ApplicationRecord
  has_many :group_users, dependent: :destroy
  has_many :users, through: :group_users # group.usersが利用可能に

  # バリデーション
  validates :name, presence: true
  validates :introduction, length: { maximum: 50 }
  validates :owner_id, presence: true

  has_one_attached :group_image

  # 画像を取得するメソッド
  def get_group_image(weight, height)
    unless self.group_image.attached?
      file_path = Rails.root.join('app/assets/images/no_image.jpg')
      group_image.attach(io: File.open(file_path), filename: 'default-image.jpg', content_type: 'image/jpeg')
    end
    self.group_image.variant(resize_to_fill: [weight, height]).processed
  end

  # ユーザーがグループに参加しているかを判定
  def joined_by?(user)
    group_users.exists?(user_id: user.id)
  end
end

3. ルーティングの設定

次に、ルーティングにグループとそのユーザー管理用のルートを追加します。

routes.rb
resources :groups do
  resource :group_users, only: [:create, :destroy] # グループへの参加と離脱
end

Untitled.png

4. グループ作成・一覧ページへのリンクを追加

ユーザー一覧ページに、グループ作成ページへのリンクとグループ一覧ページへのリンクを追加します。
image.png

users/index.html.erb
    :
    <div class='col-md-8 offset-md-1'>
      <h2>Users</h2>
      <%= link_to "グループを作成する", new_group_path %> | <%= link_to "グループ一覧", groups_path %>
      <%= render 'index', users: @users %>
    </div>
  </div>
</div>

5. Viewファイルの作成

・グループ作成ページ
image (1).png

groups/new.html.erb
<div class='container'>
  <div class='row'>
    <div class="col-sm-12 col-md-8 col-lg-5 px-5 px-sm-0 mx-auto">
      <h2>Group Creation</h2>
      <%= form_with model: @group, local: true do |f| %>
        <div class="form-group">
          <%= f.label :name %>
          <%= f.text_field :name, class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :introduction %>
          <%= f.text_area :introduction, class: "form-control" %>
        </div>
        <%= f.submit "Create Group", class: "btn btn-primary" %>
      <% end %>
    </div>
  </div>
</div>

・グループ一覧ページ
image (2).png

groups/index.html.erb
<div class='container px-5 px-sm-0'>
  <div class='row'>
    <div class='col-md-8 offset-md-1'>
      <h2>Groups</h2>
      <%= render 'index', groups: @groups %>
    </div>
  </div>
</div>

・グループ編集ページ
image (3).png

groups/_index.html.erb
<table class='table'>
  <thead>
    <tr>
      <th></th>
      <th>グループ名</th>
      <th>紹介文</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <% @groups.each do |group| %>
      <tr>
        <td><%= image_tag group.get_group_image(80, 80) %></td>
        <td><%= link_to group.name, group_path(group.id) %></td>
        <td><%= group.introduction %></td>
        <% if group.owner_id == current_user.id %>
          <td><%= link_to 'Edit', edit_group_path(group.id), class: "btn btn-sm btn-success" %></td>
        <% end %>
      </tr>
    <% end %>
  </tbody>
</table>

6. Controllerの設定

最後に、グループ管理用のGroupsControllerGroupUsersControllerを作成します。

groups_controller.rb
class GroupsController < ApplicationController
  before_action :authenticate_user!
  before_action :ensure_correct_user, only: [:edit, :update, :destroy] #グループオーナーでないと:edit, :update, :destroyは使えない

  def new
    @group = Group.new
  end

  def create
    @group = Group.new(group_params) #グループ新規作成
    @group.owner_id = current_user.id #owner_idの代入
    if @group.save
      redirect_to groups_path, notice: "You have created group successfully."
    else
      render 'new'
    end
  end

  def index
    @groups = Group.all
  end

  def show
    @group = Group.find(params[:id])
    @users = @group.users #@groupに入っているユーザーのみ格納
    @owner_user = User.find(@group.owner_id) #グループオーナーを見つけて格納
  end

  def edit
  end

  def update
    if @group.update(group_params)
      redirect_to groups_path, notice: "You have updated group successfully."
    else
      render 'edit'
    end
  end

  private

  def group_params
    params.require(:group).permit(:name, :introduction, :group_image)
  end

  def ensure_correct_user #グループオーナーかどうかを判断する
    @group = Group.find(params[:id])
    unless @group.owner_id == current_user.id
      redirect_to groups_path
    end
  end
end
group_users_controller.rb
class GroupUsersController < ApplicationController
  # グループにユーザーを参加させるアクション
  def create
    # 加入しようとしているグループを検索する
    group = Group.find(params[:group_id])
    # group_userにuser_id、group_idを格納
    group_user = current_user.group_users.new(group_id: group.id)
    # ユーザーをグループに加入
    group_user.save
    redirect_to groups_path
  end

  # グループからユーザーを脱退させるアクション
  def destroy
    # 脱退しようとしているグループを検索する
    group = Group.find(params[:group_id])
    # group_userにuser_id、group_idを格納
    group_user = current_user.group_users.find_by(group_id: group.id)
    # ユーザーをグループから脱退させる
    group_user.destroy
    redirect_to groups_path
  end
end

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?