💭

【Rails】いいね機能(非同期通信)

2023/10/04に公開

非同期通信を用いていいね機能を実装します。

非同期通信とは

送信者のデータ送信タイミングと受信者のデータ受信タイミングを合わせずに通信を行う通信方式を指します。TwitterやFacebookでの「いいね」ボタンのイメージになります。
JavaScriptによって非同期通信を行うことをAjaxといいます。
Ajaxを使うことで、Webページ全体を更新することなく「一部分だけ情報を更新する」ことが可能になります。

jQueryをインストール

Gemfile.
gem 'jquery-rails'

Gemfileに上記を記述し、JavascriptのライブラリであるjQueryをインストールします。ターミナルにて「bundle install」を忘れずに!

Viewファイル作成

  • いいね機能は部分テンプレートに!
    favorites内に部分テンプレートを作成します。
viws/favorites/_btn.html.erb
<% if book.favorited_by?(current_user) %>
   <%= link_to book_favorites_path(book.id), method: :delete, remote: true do %><%= book.favorites.count %>
   <% end %>
   <% else %>
   <%= link_to book_favorites_path(book.id), method: :post, remote: true do %><%= book.favorites.count %>
   <% end %>
<% end %>

remote: trueはlink_toに加えることで自動的に Ajax での処理にすることができます。
そのためページがリロードされることなく変更を反映することができます。

  • idを追加
    一覧ページ
viws/books/_index.html.erb
・
・
<tbody>
    <% books.each do |book| %>
      <tr>
        <td><%= link_to(book.user) do %>
          <%= image_tag book.user.get_profile_image, size:'50x50' %>
          <% end %>
        </td>
        <td><%= link_to book.title,book %></td>
        <td><%= book.body %></td>
      + <td id="favorite_btn_<%= book.id %>">
        <%= render "favorites/btn", book: book %>
        </td>  
        <td>コメント数: <%= book.book_comments.count %>
        </td>
      </tr>
    <% end %>
  </tbody>
  ・
  ・

<td id="favorite_btn_<%= book.id %>">は後に作成するjs.erbファイルの記述に更新したい箇所の指定が必要となるため、tdタグにHTMLのidで名前を付けます。

詳細ページ

viws/books/show.html.erb
<h2>Book detail</h2>
<table class='table'>
・
・
  <td id="favorite_btn_<%= @book.id %>">
 + <%= render "favorites/btn", book: @book %>
   </td> 
</table> 
・
・

一覧同様、詳細にも記載

Controllerのリダイレクト先を削除

app/controllers/favorites.html.erb
class FavoritesController < ApplicationController
  
  def create
    @book = Book.find(params[:book_id])
    favorite = current_user.favorites.new(book_id: @book.id)
    favorite.save
    # redirect_to request.referer
  end

  def destroy
    @book = Book.find(params[:book_id])
    favorite = current_user.favorites.find_by(book_id: @book.id)
    favorite.destroy
    # redirect_to request.referer
  end
  
end

非同期通信を行う場合は、JavaScriptファイル(.js.erb)を使用してビューを更新します。そのため、redirect_toを削除することによりアクション内にrenderredirect_toの記述がない場合、Railsは自動的に対応するJavaScriptファイルを探しに行きます。

【前提事項】

  • renderやredirect_toを書かない場合は、アクション名.js.erbが必要になります。
  • Viewの<%= @book.id %>はfavorites_controllerで呼び出されています。そのためfavorites_controllerのアクション内で@bookが定義されている必要があります。

jsファイルの作成

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

作成中のトラブル

僕自身が作成中に起きたトラブルを1件紹介します。本機能ではなく、いいね機能の部分テンプレートにて発生したトラブルです。

いいねボタンを押すといきなり別のところにボタンが発生しました。
更新をすると元の画面に戻り、いいねの数は正しい数字となっていました。

原因は部分テンプレート内の記述を<td>タグで囲っていたことでした。差し込まれるview画面とタグが重複してしまい起きる現象でした。
今回のように機能的な差し込みを目的とした部分テンプレート内では基本的タグはいらないとのこと。初歩的なところではありますが同じ過ちを繰り返さないためにもここに記します笑

他にもコントローラーのアクション内にインスタンス変数が定義されておらず更新されない等ありましたが、非同期通信ではエラー画面が表示されません。代わりにターミナルに出力されることが多いとのことですので、不具合があればターミナルの確認をおすすめします。

参考ページ

すぎさん
がんもさん
sayaさん

Discussion