🍈

Rails いいね機能の非同期通信化

2023/05/01に公開

「Ajax」とは

JavaScript(Ajaxを構成する中核)を使って、非同期にサーバー間での通信を行うこと。

例えば、ページを再読み込みしたり、「送信」ボタンは押していないのに、TwitterやFacebookで「いいね」ボタンを押すと、すぐに「いいね」アイコンに変わること。
Ajaxを使うことで、Webページ全体を更新することなく「一部分だけ情報を更新する」ことが可能になる。

https://zenn.dev/goldsaya/articles/8cb59d49659338
https://qiita.com/hisamura333/items/e3ea6ae549eb09b7efb9

非同期の処理の流れ

  • ユーザーがいいねをクリックする
    (Webブラウザ)

  • ルーティングでどのコントローラのどのアクションを呼び出すか決める

  • アクションを実行する(いいねの保存や削除)

  • コントローラ名・アクション名・js.erbファイル内の処理を実行する
    (部分的にページを更新)

  • レスポンスを返す
    (Webブラウザ)

jQueryの読み込み

Gemfile.
gem 'jquery-rails'

bundle install を忘れずに行う。

部分テンプレート作成&いいねボタンにAjaxの処理を適用

部分テンプレートで作成しました。

_favorite.html.erb
<% if book.favorited_by?(current_user) %>
  <p>
    <%= link_to book_favorites_path(book), method: :delete, remote: true, data: {"turbolinks" => false} do %>
      <i class="fas fa-heart" aria-hidden="true" style="color: red;"></i>
      <span style="color: red;"><%= book.favorites.count %></span>
    <% end %>
  </p>
  <% else %>
  <p>
      <%= link_to book_favorites_path(book), method: :post, remote: true, data: {"turbolinks" => false} do %>
        ♡<%= book.favorites.count %>
      <% end %>
  </p>
<% end %>

link_to内にremote; true を追加することで、
HTMLリクエストではなく、JavaScriptのリクエストがfavoritesコントローラに送られる!!

HTMLリクエストの場合
→データベースにいいねを保存or削除し、画面にリダイレクト(ページを読み込む)
JavaScriptリクエストの場合
→データベースにいいねを保存or削除し、JavaScriptを使っていいね部分のみ更新(ページ読み込みなし)

https://pikawaka.com/rails/remote-true#2.リクエストされるフォーマットで処理を分ける

data: {"turbolinks" => false}
turbolinksを限定的に動かないようにするために記入。この記入がないと、リロードしないと反映されなくなる。

books/_index.html.erb
:
	省略
:	
<tbody>
    <% books.each do |book| %>
      <tr>
        <td><%= link_to book.user do %>
          <%= image_tag book.user.get_profile_image(50, 50) %>
          <% end %>
        </td>
        <td><%= link_to book.title,book, class: "book_#{book.id}" %></td>
        <td><%= book.body %></td>
	
	<!--いいね機能ajax-partial-->
        <td id="favorite_buttons_<%= book.id %>" >
            <%= render "favorites/favorite", book: book %>
        </td>
        <td><p>コメント件数:<%= book.post_comments.count %></p></td>
        <td><%= render "books/static_rate", book: book %></td>
      </tr><% end%>

この箇所の更新を指定するために、変更したい箇所にidで名前をつけている。

いいね保存、削除のリダイレクト先を削除

favorites_controller
class FavoritesController < ApplicationController
  def create
    @book = Book.find(params[:book_id])
    favorite = @book.favorites.new(user_id: current_user.id)
    favorite.save
    #redirect_back(fallback_location: root_path)
  end

  def destroy
    @book = Book.find(params[:book_id])
    favorite = current_user.favorites.find_by(book_id: @book.id)
    favorite.destroy
    #redirect_back(fallback_location: root_path)
  end
end

リダイレクト先を削除したことにより、
リダイレクト先がない&JavaScriptリクエストという状況になり、

createアクション実行後は、create.js.erbファイルを、
destroyアクション実行後はdestroy.js.erbファイルを探してくれる。

部分テンプレートを読み込む

books/show.html.erb
<td id="favorite_buttons_<%= @book.id %>" >
  <%= render "favorites/favorite", book: @book %>
</td>

この箇所の更新を指定するために、変更したい箇所にidで名前をつける。
  id="favorite_buttons_<%= book.id %>"

js.erbファイルの編集

favorites/create.js.erb
$('#favorite_buttons_<%= @book.id %>').html("<%= j(render "favorites/favorite", book: @book) %>");
favorites/destroy.js.erb
$('#favorite_buttons_<%= @book.id %>').html("<%= j(render "favorites/favorite", book: @book) %>");

急いで書いたので抜けているところがあるかもしれないです><
今日はここまで。

参考にさせていただいた記事
https://qiita.com/hapiblog2020/items/3ba7e7edc02f01d987b9

Discussion