[Ruby on rails]グループ作成①

<h2>初めに</h2>
プログラミング学習初めて1ヶ月と少しです。
理解不足、誤りがありましたらご指摘いただけますと幸いです。


<h2>グループ作成機能①</h2>
本の投稿サイトを作成しています。①の今回は、グループを作れるようにします。
この記事ではあるユーザーがグループを作る流れをまとめています。
グループに参加する機能は無いです。それは②でやります。

<h3>今回の記事でできるようになること</h3>
*グループを作成するリンクの表示。
＊グループを作れる。（②の記事でメンバー増やせるようにします）
*作成した人はグループオーナー
＊グループ一覧画面作成。
*グループのオーナーであればグループの編集ができる
＊グループの詳細画面（①の段階では質素な画面です。）

グループの編集は、グループの作成者のみが行えます。（削除機能は無しです。）
画面は以下の４つ。
グループ一覧画面。
グループ詳細画面。
グループ編集画面。
グループ作成画面。

「作成イメージ」

![スクリーンショット 2021-07-08 17.46.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/9c15809f-c568-bf95-6deb-de60208cb64c.png)


<h2>まずアソシエーション考える</h2>
ユーザー：Group= 1:N（複数）
Group:ユーザー=1:N（複数）　なので、中間テーブルが必要になります。
中間テーブルは、GroupUserとして、外部キーとしてuser_idとgroup_idを持たせます。

Groupテーブルのカラムは
id
name
introduction
image_id (グループ画像も設定可能にします！）
owner_id （グループ作成者をowner_idにします）

<h2>作成開始</h2>

```$ rails g controller groups
$ rails g model group
$ rails g model group_user```
中間テーブルであるgroup_userは何かするわけではなく、groupとユーザーの外部キーを持ってくれてるだけなので、コントローラーはいりません。

<h2>マイグレーションファイルの内容</h2>

```perl:20~~??_create_groups.rb
class CreateGroups < ActiveRecord::Migration[5.2]
  def change
    create_table :groups do |t|
      t.string :name
      t.text :introduction
      t.string :image_id
      t.integer :owner_id

      t.timestamps
    end
  end
end
```

```perl:20~~??_create_group_users.rb
class CreateGroupUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :group_users do |t|
      t.references  :user,  index: true, foreign_key: true
      t.references  :group, index: true, foreign_key: true
      
      t.timestamps
    end
  end
end
```

ここの記述は簡単にいうと、group_usersに外部キーとしてuser_idとgroup_idを登録しています。以下の記事がわかりやすかったです。reference使えば、自動でindexもひっぱってくるということなので、```index:true```はなくても良いようです。


https://qiita.com/ryouzi/items/2682e7e8a86fd2b1ae47

忘れずにマイグレーション！

```
rails db:migrate
```

<h2>モデルファイルにアソシエーション記述</h2>

グループの削除機能はないので、dependent: :destroyの記述はないです。

```perl:group_user.rb
class GroupUser < ApplicationRecord
  belongs_to :user
  belongs_to :group
end
```
```perl:group.rb
class Group < ApplicationRecord
  has_many :group_users
  has_many :users, through: :group_users

  validates :name, presence: true
  validates :introduction, presence: true
  attachment :image, destroy: false
end
```

現状、destroy:falseがわかりませんdestroyはできない　という意味なのでしょうか。


```perl:user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :books
  has_many :group_users   #ここ！
  has_many :groups, through: :group_users
  has_many :favorites, dependent: :destroy
  has_many :book_comments, dependent: :destroy
  attachment :profile_image, destroy: false

  validates :name, length: { minimum: 2, maximum: 20 }, uniqueness: true
  validates :introduction, length: { maximum: 50 }
end
```

```has_many :groups, through: :group_users```
これは、userは、group_usersという中間テーブルを通じてgroupsにアクセスできるという記述。
Userのボス「そりゃーグループの情報掴めるよ〜group_usersを通じて聞けばいいんだよ」みたいな。group_usersさんは仲介役ですね。
なんだか、ちんぷんかんだった中間テーブルがわかってきたような気がします。
Userのボスからしてみても、中間テーブルという仲介役がいた方がラクなんですよね。


https://web-camp.io/magazine/archives/17680


<h2>ルーティングの設定</h2>

```
resources :groups, except: [:destroy]
```
もちろん
```only: [:index, :show, :edit, :create, :update, :new, :show] 
```のような記述でもいけると思います。


<h2>コントローラー作成</h2>


```perl:groups_controller.rb
class GroupsController < ApplicationController
  before_action :authenticate_user!
  before_action :ensure_correct_user, only: [:edit, :update]

  def index
    @book = Book.new
    @groups = Group.all
  end

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

  def new
    @group = Group.new
  end

  def create
    @group = Group.new(group_params)
    @group.owner_id = current_user.id
    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

  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
end
```
本の投稿サイトなので、@book等の記述も入ってしまっています。

<h2>Viewページ</h2>

![スクリーンショット 2021-07-08 17.43.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/447c5034-fb90-c667-b4d1-d56855c095db.png)

↑の部分の記述。
![スクリーンショット 2021-07-08 17.45.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/3b0be8ca-f1be-7c92-5cea-35a37b0bcb19.png)

```
<div><%=link_to "グループを作成する",new_group_path %> | <%=link_to "グループ一覧",groups_path %></div>
```


<details><summary>その他のview</summary><div>

部分テンプレートで飛ばしています。




```perl:edit.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">
      <h3>Editing Group</h3>
        <%= render 'form', group: @group %>
  </div>
</div>
```

```perl:_form.html.erb
<%= form_with model: group, local: true do |f| %>
  <div class="form-group">
    <%= f.label :グループ名 %>
    <%= f.text_field :name, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :紹介文 %>
    <%= f.text_area :introduction, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :グループ画像 %>
    <%= f.attachment_field :image, class: "form-control-file" %>
  </div>

  <div class="form-group">
    <%= f.submit class: 'btn btn-info' %>
  </div>
<% end %>
```

```perl:index.html.erb
#関連部分のみ
<div class='col-md-8 offset-md-1'>
      <h2>Groups</h2>
      <table class='table table-hover table-inverse'>
        <thead>
          <tr>
            <th></th>
            <th>グループ名</th>
            <th>紹介文</th>
            <th colspan="3"></th>
          </tr>
        </thead>
        <tbody>
          <% @groups.each do |group| %>
            <tr>
              <td><%= attachment_image_tag(group, :image, :fill, 50, 50, fallback: "no-image-icon.jpg") %></td>
              <td><%= link_to group.name, group_path(group) %></td>
              <td><%= group.introduction %></td>
              <td>
                <% if group.owner_id == current_user.id %>
                  <%= link_to 'Edit', edit_group_path(group), class: "btn btn-sm btn-success" %>
                <% end %>
              </td>
            </tr>
          <% end %>
        </tbody>
      </table>
    </div>
```

```perl: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">
      <h3>Create Group</h3>
        <%= render 'form', group: @group %>
    </div>
  </div>
</div>
```

```perl:show.html.erb
<div class='container px-5 px-sm-0'>
  <div class='row'>
    <div class='col-md-3'>
      <h2>User info</h2>
      <%= render 'users/info', user: current_user %>
      <h2 class="mt-3">New book</h2>
      <%= render 'books/form', book: @book %>
    </div>
    <div class='col-md-8 offset-md-1'>
      <h2>Group Detail</h2>
      <table class='table table-hover table-inverse'>
        <tr>
          <td><%= attachment_image_tag(@group, :image, :fill, 50, 50, fallback: "no-image-icon.jpg") %></td>
          <td><%= @group.name %></td>
          <td><%= @group.introduction %></td>
          <td>
            <% if @group.owner_id == current_user.id %>
              <%= link_to 'Edit', edit_group_path(@group), class: "btn btn-sm btn-success" %>
            <% end %>
          </td>
        </tr>
      </table>
    </div>
  </div>
</div>
```
</div></details>

<h2>終わり</h2>
これを見ながら、再度実装したところ、なんとかできましたので、
問題ないかと思います！