コメント機能の実装

備忘録です！！

##Commentモデル作成

userとboardに紐ずいたcommentモデルを作成します。

```ruby:ターミナル
rails g model Comment body:text user:references board:references
```

##他モデルとのアソシエーションを追加
commentモデルとuser,boardモデルとのアソシエーションを追加します。

references型を用いたので、blongs_toは最初から記載されています。

```ruby:user.rb
has_many :comments, dependent: :destroy
has_many :boards, dependent: :destroy
```

```ruby:board.rb
has_many :comments, dependent: :destroy
```

##ルーティングを追加

今回は、boardのルーティングをネストしていきます。

```ruby:routes.rb
references :boards, only: %i[index new create show] do
  references :comments, only: %i[create], shallow: true
```

```ruby:ターミナル 
board_comments POST   /boards/:board_id/comments(.:format)                                                     comments#create
        boards GET    /boards(.:format)                                                                        boards#index
               POST   /boards(.:format)                                                                        boards#create
     new_board GET    /boards/new(.:format)                                                                    boards#new
         board GET    /boards/:id(.:format)                                                                    boards#show
```

shallowをtrueにしてpathを綺麗にします。


##commentコントローラーを作成

```ruby:ターミナル 
rails g controller Comments
```

```ruby:comments.controller
def create
  comment = current_user.comments.build(comment_params)
  comment.board_id = params[:board_id]
  if comment.save
    redirect_to board_path(params[:board_id]), success: t('defaults.message.created', item: Comment.model_name.human)
  else
    redirect_to board_path(params[:board_id]), danger: t('defaults.message.not_created', item: Comment.model_name.human)

def comment_params
  params.require(:comment).permit(:body, board_id)
```

コメントが保存できたら、掲示板詳細ページに移動するようにします。
この辺は、掲示板投稿機能の実装とそこまで変わりません。

##boardコントローラー
掲示板の詳細ページでコメントのデータを取得します。

```ruby:boards.controller
def show
  @board = Board.find(params[:id])
  @comment = current_user.comment.new
  @comments = @board.comments.includes(:user).order(created_at: :desc)
```

これで、コメントのデータと投稿のデータを取得でき、さらにコメントが、投稿時間順に表示されます。

##viewの追加

viewを追加していきます。

今回は、コメントの表示、コメント投稿フォームはパーシャルで作成していきます。

```ruby:board/show.html.erb
<div class="container pt-5">
  <div class="row mb-3">
    <div class="col-lg-8 offset-lg-2">
      <h1><%= t('.title') %></h1>
      <!-- 掲示板内容 -->
      <article class="card">
        <div id="broad-id-<%= @board.id %>">
          <div class="card-body">
            <div class='row'>
              <div class='col-md-3'>
                <%= image_tag @board.board_image.url, class: 'card-img-top img-fluid', size: '300x200' %>
              </div>
              <div class='col-md-9'>
                <h3 class="d-inline"><%= @board.title %></h3>
                  <ul class='list-inline float-right'>
                    <li class="list-inline-item">
                      <%= link_to '#', id: 'button-edit-#{board.id}' do %>
                        <%= icon 'fa', 'pen' %>
                      <% end %>
                    </li>
                    <li class="list-inline-item">
                      <%= link_to '#', id: 'button-delete-#{board.id}', method: :delete, data: {confirm: ''} do %>
                        <%= icon 'fas', 'trash' %>
                      <% end %>
                    </li>
                  </ul>
                <ul class="list-inline">
                  <li class="list-inline-item">by <%= @board.user.decorate.full_name %></li>
                  <li class="list-inline-item"><%= l @board.created_at, format: :long  %></li>
                </ul>
              </div>
            </div>
            <p><%= simple_format(@board.body) %></p>
          </div>
        </div>
      </article>
    </div>
  </div>

  <!-- コメントフォーム -->
  <%= render 'comments/form', { board: @board, comment: @comment } %>

  <!-- コメントエリア -->
  <div class="row">
    <div class="col-lg-8 offset-lg-2">
      <table id="js-table-comment" class="table">
        <%= render partial: 'comments/comment', collection: @comments %>
      </table>
    </div>
  </div>

  
</div>
```

```ruby:comment/_comment.html.erb
<tr id="comment-<%= comment.id %>">
  <td style="width: 60px">
    <%= image_tag 'sample.jpg', class: 'rounded-circle', size: '50x50' %>
  </td>
  <td>
    <h3 class="small"><%= comment.user.decorate.full_name %></h3>
    <div id="js-comment-<%= comment.id %>">
      <%= simple_format(comment.body) %>
    </div>
  </td>

  <% if current_user == comment.user %>
    <td class="action">
      <ul class="list-inline justify-content-center" style="float: right;">
        <li class="list-inline-item">
          <a href="#" class='js-edit-comment-button' data-comment-id="<%= comment.id %>">
            <%= icon 'fa', 'pen' %>
          </a>
        </li>
        <li class="list-inline-item">
          <a href="#" class='js-delete-comment-button' data-comment-id="<%= comment.id %>">
            <%= icon 'fas', 'trash' %>
          </a>
        </li>
      </ul>
    </td>
  <% end %>
</tr>
```

```ruby:comment/_form.html.erb
<div class="row mb-3">
  <div class="col-lg-8 offset-lg-2">
    <%= form_with model: [board, comment], local: true do |f| %>
      <%= render 'shared/error_messages', object: f.object %>
      <%= f.label :body %>
      <%= f.text_area :body, class: 'form-control mb-3', id: 'js-new-comment-body', row: 4, placeholder: Comment.human_attribute_name(:body) %>
      <%= f.hidden_field :board_id, value: @board.id %>
      <%= f.submit t('defaults.post'), class: 'btn btn-primary' %>
    <% end %>
  </div>
</div>
```

部分テンプレートの再現性が下がってしまうため、コメントの表示のパーシャルには、インスタンス変数ではなく、ローカル変数を用いました。