コメント機能の非同期化

**book投稿アプリ作成中**
:hatching_chick:**はじめに、非同期とは？**
非同期リクエストは、ウェブアプリケーションで特定の操作（例: コメントの作成や削除）を行う際に使用される方法です。この方法では、ページの更新や再読み込みをせずに、データの送受信を行うことができます。

**:point_up:前提条件**
・device導入　・Bootstrap導入
・ユーザー機能実装済（Userモデル）
・投稿機能実装済（Bookモデル）
・コメント機能実装済（Book_Commentモデル）
_____
**jQueryインストール**
``Gemfile``に以下を追加
```
gem "jquery-rails"
```
``javascript/packs/application.js``に以下を追加
```
import "jquery";
```
**インストール**
```
$ bundle install
```
____
今回、部分プレートにする元のshowページです。
```diff_ruby
 <!--コメント機能-->
        <div>
          <table>
         <% @book.book_comments.each do |book_comment| %>
          <tr>_
            <td>
             <%= link_to user_path(@book.user.id) do %>
             <%= image_tag book_comment.user.get_profile_image(50,50) %><br>
             <%= @book.user.name %>
             <% end %>
             </td> 
             <td><%= book_comment.comment %></td> 
             <td>
              <% if book_comment.user == current_user %>
              <%= link_to "Destroy", book_book_comment_path(book_comment.book,book_comment), method: :delete, class: "btn btn-sm btn-danger"%>
              <% end %>
             </td>
           </tr>
         <% end %>
         </table>
        </div>
          
          <div>
             <%= form_with model: [@book, @book_comment] do |f| %>
             <%= f.text_area :comment, rows: '5',placeholder: "コメントをここに", class: "form-control comment" %>
             <%= f.submit "送信", class: "btn btn-lg btn-base-1 mt-20 pull-right" %>
            <% end %>
          </div>
```
**コメント機能用の部分テンプレートを作成**
今回は、book_commentsディレクトリ内に
``_comment.html.erb``を作成しました。

books/show.html.erbのコメント機能部分を部分テンプレートへ変更する。

:star:form_withへ**lacal: false**と記述することで、javascript形式になります。
（**local: true**だとHTML形式となります。）

:star:、"Destroy"の<%= link_to のところに、**remote: true**を追記すること

javascript形式でリクエストを送ることでページをリロードせずに一部のみ変更が可能です。


``_comment.html.erb``
```diff_ruby
<!--コメントリスト部分プレート-->
  <table>
    <% book.book_comments.each do |book_comment| %>
      <tr>
        <td>
          <%= link_to user_path(book.user.id) do %>
            <%= image_tag book_comment.user.get_profile_image(50,50) %><br>
            <%= book.user.name %>
          <% end %>
        </td> 
        <td><%= book_comment.comment %></td> 
        <td>
          <% if book_comment.user == current_user %>
          <!--remote: trueを追加-->
+           <%= link_to "Destroy", book_book_comment_path(book_comment.book,book_comment), method: :delete,remote: true, class: "btn btn-sm btn-danger"%>
          <% end %>
        </td>
      </tr>
    <% end %>
  </table>

   <!--コメントフォーム部分プレート-->
   <!--local: falseを追加-->
+  <%= form_with(model: [book, book_comment], local: false, class: "comment-form") do |f| %>
    <%= f.text_area :comment, rows: '5', class: "form-control comment" %>
    <div>
      <%= f.submit "送信" %>
    </div> 
  <% end %>
```
:shamrock:追加した部分テンプレートをshowページに呼び出す。
非同期化にするときはidを指定する。

```diff_ruby
 <div id="comment_area">
         <%= render "book_comments/comment", book: @book, book_comment: @book_comment %>
```
____
:shamrock:**javascriptのファイル作成**

book.commentディレクトリ内に作成（コントローラーのアクション名で作成する。）
``create.js.erb``&``destroy.js.erb``を作成

``create.js.erb``
```diff_ruby
$("#comment_area").html("<%=j(render 'book_comments/comment', book: @book, book_comment: @book_comment)%>");
```

``destroy.js.erb``
```diff_ruby
$("#comment_area").html("<%=j(render 'book_comments/comment', book: @book, book_comment: @book_comment)%>");
```
:point_up:comment_areaの部分は、showページで指定したidです。
___
:shamrock:**コントローラー変更**

:star:ユーザーがページを更新せずにデータの送受信を行うため、
ページのリダイレクトは不要なので、**redirect_to**の部分を削除する。
:star:非同期リクエストでは、JavaScriptやAJAXを使用してデータの送受信が行われます。

:star:Javascriptのファイルで@book と @book_commentを渡しているので、
book_commentsコントローラーでこの値を定義する。（今回は、booksのshowページを参考に）

:star: **@book_comment = BookComment.new**を指定することで投稿、削除後に投稿内容が残らないようにしています。

``book_comments_controller.rb``
```diff_ruby
class BookCommentsController < ApplicationController
  def create
    book = Book.find(params[:book_id])
    comment = current_user.book_comments.new(book_comment_params)
    comment.book_id = book.id
    comment.save 
+   @book = Book.find(params[:book_id])
+   @book_comment = BookComment.new
-   redirect_to book_path(book)
  end
  
  def destroy
    BookComment.find(params[:id]).destroy
+    @book = Book.find(params[:book_id])
+   @book_comment = BookComment.find_by(id: params[:id], book_id: params[:book_id])
+   @book_comment = BookComment.new
-   redirect_to book_path(params[:book_id])
  end
  
  private
  def book_comment_params
    params.require(:book_comment).permit(:comment)
  end
end
```
**books/showアクション**
```diff_ruby
def show
    @book = Book.find(params[:id])
    @user = @book.user
    @book_new = Book.new
    @book_comment = BookComment.new 
  end
```

_____

:hamster:**ひとこと**
非同期化中にコントローラーにrenderを追加してしまい、
無限にコメントが作成されてしまいました。:sweat_smile:
作成されたデータを削除するには、
``rails db:migrat:reset``を実行しましょう！

jsファイルに渡す値を間違えないように！

:star2:**完成イメージ**
https://i.gyazo.com/de489f96f9200ea9764eed5fafbb10f4.mp4