初学者メモ　Rails グループ作成機能

# はじめに
「コミュニティアプリにグループ作成機能を実装したい」
「グループへ自由に入会、退会できるようにしたい」
初学者のメモです
### 実装した主な機能
- オーナーによるグループ作成、削除
- グループ情報は、「イメージ画像」「グループ名」「グループ説明」
- オーナー以外のグループへの入会、退会

# 手順
1. アソシエーション
1. ルーティング
1. コントローラー（グループ作成）
1. コントローラー（グループ入会、退会）

# 実装
## ER図
diagrams.netで作成
![スクリーンショット 2023-06-04 10.05.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348867/4599af24-a3d2-b7b4-5b3a-009d5e9c6b13.png)
- このイメージで実装していきます
- 元々、Userモデルがある状態です
- Userにownerカラムを持たせるか悩みました（結局、必要なかったです）

## ① アソシエーション
```:user.rb
#省略
has_many :group_users, dependent: :destroy
has_many :groups, through: :group_users
#省略
```
- userは中間テーブルgroup_usersを介して、groupsを持っているというイメージ
- ブックマーク機能やフォロー機能との関連性を感じます
##### 過去にフォロー機能を作成したときのもの
![スクリーンショット 2023-06-04 11.45.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348867/fa5224b2-baf2-65b7-fedc-564a4ea4ec8c.png)

```:group.rb
belongs_to :owner, class_name: 'User'
has_many :group_users, dependent: :destroy
has_many :users, through: :group_users, source: :user
validates :name, presence: true
validates :introduction, presence: true
has_one_attached :image

def get_image
  (image.attached?) ? image : 'no_image.jpg'
end
```
- `belongs_to :owner, class_name: 'User'`は、groupはownerを持っていて、それは、userモデルにあるというイメージ。中間テーブルにowner_idがあることで実現できる
- groupは中間テーブルgroup_usersを介して、usersを持っているというイメージ。ここも、ブックマーク機能やフォロー機能との関連性を感じます
- バリデーションもOK
- 今回は、Active Recordにimageカラムを持たせたため、`has_one_attached :image
`の記述と、`get_image`のアクション定義をしています。画像添付がない場合は、no_image.jpgを参照

```:group_user.rb
belongs_to :user
belongs_to :group
```

## ②ルーティング
```:routes.rb
resources :groups do
  resource :group_users, only: [:create, :destroy]
end
```
- Groupについては、デフォルトのアクションを全て可能にしました
- group_usersについては、「create=グループ入会」「destroy=グループ退会」のみにしました

## ③コントローラー（グループ作成）
```:groups_controller/rb
before_action :authenticate_user!
before_action :ensure_correct_user, only: [:edit, :update]

def new
  @group = Group.new
end

def index
  @groups = Group.all
end

def show
  @group = Group.find(params[:id])
end

def create
  @group = Group.new(group_params)
  @group.owner_id = current_user.id
  @group.users << current_user
    if @group.save
      redirect_to groups_path
    else
      render 'new'
    end
end

def edit
end

def update
  if @group.update(group_params)
    redirect_to groups_path
  else
    render "edit"
  end
end

def destroy
  @group = Group.find(params[:id])
  @group.destroy
  redirect_to groups_path
end

private

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

def ensure_correct_user
  @group = Group.find(params[:id])
  unless @group.owner_id == current_user.id
    redirect_to groups_path
  end
end
```
- `@group.users << current_user`で、現在のユーザーをグループのユーザー数に追加しました
- これで、グループのcreateもdestroyも可能になります

## ④コントローラー（グループ入会、退会）
```:group_users_controller.rb
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
```
- `find_by(group_id: params[:group_id])`では、find_byメソッドでによって、group_idを指定しました
- HTTPリファラを取得してリダイレクトさせる`redirect_to request.referer`が個人的に便利で好きです
- 後は、ビューファイルの記述

# まとめ
- グループ機能は中間テーブルを用いて、N対Nのリレーションを実装する
- グループ作成はgroupsに、入会や退会はgroup_usersにアクションを記述する

投稿4回目。
ボリューミーで、整理するのが難しかったです。
今後、グループ内での様々な機能を試していきます。
ご指導、ご教授いただけると幸いです。