RailsでAjaxでいいね機能を実装する方法

<a href="https://qiita.com/Yusuke_Hoirta/items/a509b389b5f8a705be61">「Railsでいいね機能を実装する方法」</a>でいいね機能の実装方法をご紹介しましたが、今回はそのいいね機能をAjax(非同期通信)実装する方法をご紹介いたします。
完成系は以下のような感じです。
![いいね_Ajax.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654387/92973f10-089f-3d7a-ef49-b7e06f1a83a5.gif)


# 環境
- Ruby 2.5.7
- Rails 5.2.4

# 前提
- <a href="https://qiita.com/Yusuke_Hoirta/items/a509b389b5f8a705be61">この記事</a>によって、いいね機能が実装済みであること

# index.html.erbを編集

2つのlink_to(method: :delete と method: post)に <b>remote: true</b>を追記します。
remote: trueを記載することで、Ajaxでの処理を実行することができます。

```html:index.html.erb
<div class="container">
  <h1>記事一覧</h1>
  <table class="table">
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td>
          <% if post.liked_by?(current_user) %>
            <% like = Like.find_by(user_id: current_user.id, post_id: post.id) %>
            <%= link_to like_path(like), method: :delete, remote: true do %>
              <span class="glyphicon glyphicon-heart" aria-hidden="true" style="color: red;">
              <span><%= post.likes.count %></span>
            <% end %>
          <% else %>
            <%= link_to post_likes_path(post), method: :post, remote: true do %>
              <span class="glyphicon glyphicon-heart" aria-hidden="true" style="color: gray;">
              <span><%= post.likes.count %></span>
            <% end %>
          <% end %>
        </td>
      </tr>
    <% end %>
  </table>
</div>
```

# いいね機能の部分をテンプレート化する
index.html.erbと同じディレクトリに以下のファイルを作成し、いいね機能の部分をコピーし、貼り付けます。

```html:_like.html.erb
<% if post.liked_by?(current_user) %>
  <% like = Like.find_by(user_id: current_user.id, post_id: post.id) %>
  <%= link_to like_path(like), method: :delete, remote: true do %>
    <span class="glyphicon glyphicon-heart" aria-hidden="true" style="color: red;">
    <span><%= post.likes.count %></span>
  <% end %>
<% else %>
  <%= link_to post_likes_path(post), method: :post, remote: true do %>
    <span class="glyphicon glyphicon-heart" aria-hidden="true" style="color: gray;">
    <span><%= post.likes.count %></span>
  <% end %>
<% end %>
```
部分テンプレート(_like.html.erb)を呼び出すため、いいね機能の部分があったところに<b>render</b>を記述します。
また、Ajaxの処理がされる部分を識別できるように id を記述します。

```html:index.html.erb
<div class="container">
  <h1>記事一覧</h1>
  <table class="table">
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td id="like-<%= post.id %>">  <!--idで識別できるようにする-->

　　　　   <%= render "like", post: post %>  <!--renderで部分テンプレートを呼び出す-->

        </td>
      </tr>
    <% end %>
  </table>
</div>
```

# controllerの編集
各アクションの最後にredirect_backをしていましたが、redirect_backをすると再読み込みをしていまい、Ajaxが機能しません。
そのため、redirect_backを削除します。

```ruby:likes_controller.rb
  def create
    like = Like.new(user_id: current_user.id, post_id: params[:post_id])
    @post = like.post
    like.save
  end

  def destroy
    like = Like.find(params[:id])
    @post = like.post
    like.destroy
  end
```

# jsファイルの作成
remote: trueによってjs形式のリクエストを送信しているため、実行するアクション名(createやdestroy)のjsファイルを最終的に探しに行きます。
そのため、app/views/配下にlikesフォルダを作成し、そのフォルダの中に create.js.erb と destory.js.erb を作成します。

```js:create.js.erb
$("#like-<%= @post.id %>").html("<%= j(render 'posts/like', post: @post) %>");
```

```js:destory.js.erb
$("#like-<%= @post.id %>").html("<%= j(render 'posts/like', post: @post) %>");
```
idで識別し部分的にhtmlを書き換えます。
これで完成です。