💕

Rails 非同期でいいね機能の実装

2023/04/21に公開

非同期リクエストって?

非同期リクエストとは、ページの再読み込みを行わずにサーバーとやりとりをすることで、Webページの動作を高速化する技術のこと。
Ajaxを利用することで実現され、非同期リクエストを行う際には、data: {"turbolinks" => false}を指定することで、Turbolinksが無効になるため、正しく動作することができる。

ajaxとは

Asynchronous Javascript and XMLの略
ウェブ開発において使用されるいくつかの技術の総称。

ページを更新することなくページの内容だけを入れ替えられる!

特徴

  • ページの再読み込みをしない
  • 処理の途中で他の操作もできる

例)SNSのいいねを押した後にいいねのボタンと数が変わる、マップのアプリでカーソルを移動すると、移動先の地図が連続で表示される

デメリット

  • ページを更新しないということはURLが変わらないので、変化後の情報に直接アクセスできない
  • 変更後に表示された文章は検索エンジンには引っかからないので、SEOの問題がある
  • すべてのブラウザが対応しているわけではない
  • セキュリティーやプライバーシの問題のすべてが解決しているわけではない

同期通信

  • リクエストからレスポンスの1往復が終わらないと、次のリクエストは送信する事が出来ない
  • クライアントは、リクエストしてからレスポンスが返るまで待機状態になる
  • 同期通信は、送信と受信のタイミングを合わせた通信方式のこと

今回のエラーメモ

Rails 非同期でいいね機能を作る時、
jsが読み込まれているのにページをリロードしないといいねが変わらない問題が発生!

(jsは検証ツールでエラーを見れる)

caught ReferenceError: $ is not defined
このエラーはjQueryがロードされていないために発生する可能性があることを示している!

なので、

jQuery関連の
javascript/packs/application.jsをまず確認する。

import Rails from "@rails/ujs"
// import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"
import "jquery"
import "popper.js"
import "bootstrap"
import '@fortawesome/fontawesome-free/js/all';
import "../stylesheets/application"

Rails.start()
Turbolinks.start()
ActiveStorage.start()

//= require jquery
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

私がjqueryを入れる時に何かを間違っていて、
import "jquery"

同じ意味のrequire jqueryも入ってしまっていた!
(が、これはコメントアウトになっていたので関係なかった!)

importとrequireの違い_φ(・_・
https://qiita.com/minato-naka/items/39ecc285d1e37226a283

2行目は、turbolinkが問題なんだ!と思い全体的に削除してしまっていたので復活させた。

turbolinkの記述の位置もミスっていて
部分テンプレートに下記が正しい記述で、

_favorite-btn.html

<% if book.favorited_by?(current_user) %>
   <%= 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 %>
  <% else %>
   <%= link_to book_favorites_path(book), method: :post, remote: true , data: {"turbolinks" => false}  do %>
    <i class="fas fa-heart" aria-hidden="true"></i>
    <%= book.favorites.count %>
  <% end %>
<% end %>

私はいいね機能を呼び出すrenderの部分に書いていた!

<!--いいね機能-->
          <td id="favorite-btn_<%= @book.id %>">
            <%= render 'favorites/favorite-btn', book: @book ,data: {"turbolinks" => false} %>
        </td>

data: {"turbolinks" => false}この記述はrenderにもlink_toにも使えるの?

この記述は、RailsのUJSを使用して非同期リクエストを送信する際に使用されるlink_to、button_to、form_withなどのRailsフォームヘルパーとともに使用されることが一般的。
リンクやフォームが非同期リクエストを送信した場合にTurbolinksを無効にするためのオプションを提供する。

なので、renderにはdata: {"turbolinks" => false}を使用する必要はない。

renderにはdata: {"turbolinks" => false}を使用する必要はない理由は?

renderはページの再描画を行うための処理であり、デフォルトでTurbolinksが有効になっているため、data: {"turbolinks" => false}を指定する必要はない。

なるほど、、!
Turbolinksについての理解が重要だった!
👇
https://www.techscore.com/tech/Ruby/rails-4.0/turbolinks/

あと確認するところ

config/webpack/enviroment.jsファイル!

const webpack = require('webpack')
environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: 'popper.js'
  })
)

この記述から
下記の記述に変えた!

config/webpack/enviroment.js

const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery',
    })
)

1つ目の記述では、Popper.jsをインポートし、2つ目の記述では、jQueryのソースファイルをインポートしている、らしい。

1つ目の記述では

jQueryが定義されていないために発生していると考えられるエラーが発生してしまったため
2つ目の記述が正しいぽい。


JavaScriptを学ぶ前にいきなり非同期実装しようとして
Turbolinksに惑わされてしまったが何とか理解できてよかった🥲

🌱Turbolinksについてわかりやすい説明
https://qiita.com/ginger-yell/items/740818f484bfbc1edb4d

明日Ajaxについてもっと詳しくまとめます!

Discussion