railsでの非同期通信の実装方法

railsでの非同期通信の実装方法

railsでの非同期通信の実装手順は、[remote: true]オプションを付与する方法とJSファイルに任意のタイミングでAjax処理を発火させるように記述する方法がある。

今回は、簡単な[remote: true]オプションを付与する方法を説明します。

①クライアント側で動作することでサーバーにリクエストを送る部分(link_toやform_withなど)にremote: trueと記載することで、railsの通信は非同期通信になる。


②サーバー側では、remote: trueのオプション付きでリクエストが送られてきて、いつも通り(ルーティング→コントローラーの対応しているアクション→DBへのアクセスが必要な処理の場合は、モデルに側でクエリを発行してDBへアクセス)の処理がされ、remote: trueがある事により、レスポンスのファイルは、htmlファイルではなく対応しているjsファイルがクライアントにレスポンスされる。
※非同期通信にする際は、リダイレクトやレンダーを指定しない。
リダイレクトやレンダーを指定しなければ、[app/views/コントローラ名/アクション名.js.erb]ファイルがクライアントにレスポンスされる。(js.erbファイルは、jsファイルでRuby記述も入れられるファイル。)


レスポンスとして[js.erb]ファイルを受け取った、クライアントはブラウザ上で受け取ったファイルを元にJavaScriptを実行する。

実際の具体例を以下に記述します。

[app/views ファイル]

<%= link_to bookmark_path(board.bookmarks.find_by(user_id: current_user.id)), id: "js-bookmark-button-for-board-#{board.id}", method: :delete, remote: true do %>
  <i class="fas fa-star"></i>
<% end %>

上記の記述で[link_to]に[remote: true]オプションを付与しているので、クライアント側が上記のアイコンをクリックしたら、サーバー側に非同期通信でのリクエストを送る。


  def create
    @board = Board.find(params[:board_id])
    current_user.bookmark(@board)
  end

  def destroy
    @board = current_user.bookmarks.find(params[:id]).board
    current_user.unbookmark(@board)
  end

送られてきたリクエストは、ルーティングを元に対応しているコントローラーのアクション側で処理される。
上記のようにそれぞれのアクションにリダイレクトやレンダーを記述していないので、[app/views/コントローラー名/create.js.erb]や[app/views/コントローラー名/destroy.js.erb]ファイルがクライアント側にレスポンスされる。


[app/views/bookmarks/create.js.erb]

$("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith("<%= j(render('boards/bookmark', board: @board)) %>");

上記のような場合は、まずサーバー側でrender処理をしてから、上記ファイルをクライアント側にレスポンスする。
イメージは、以下のようなものをレスポンスする感じになる。
$("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith("[app/views/boards/_bookmark.html.erb]ファイルの内容");

※ポイント
jQueryの[replaceWith]と[html]の違い
以下のようなコードがあった場合の例を示します。

[ブラウザ上でのHTML]

<div id="greeting">Hello</div>
[app/views/js.erb ファイル]

$("#greeting").replaceWith("こんにちは");

上記のような場合は、ブラウザ側で実行され以下のような結果になる。

[ブラウザ上でのHTML]

こんにちは
[app/views/js.erb ファイル]

$("#greeting").html("こんにちは");

上記のような場合は、ブラウザ側で実行され以下のような結果になる。

[ブラウザ上でのHTML]

<div id="greeting">こんにちは</div>

[replaceWith]は、対応している実際の要素($("")の部分)を全部replaceWithの引数に置き換える。
[html]は、対応している部分の要素($("")の部分)の内容を置き換える。

j(render)とは
escape_javasciptの事で、JavaScriptは[""]や['']があるとダメなので、エスケープする必要がある。

同期通信と非同期通信
・同期通信は、ブラウザとサーバーがやり取りする。
・非同期通信は、ブラウザに入っているJavaScriptがブラウザの代わりにサーバーとやり取りする。

jQueryとは
JavaScriptで出来ることを簡単に記述できるようにしたJavaScriptのライブラリ。
JavaScriptは、各ブラウザに搭載されたエンジンにより実行されるが、jQueryはブラウザ毎の記述の違いを吸収してくれる。
jQueryは、基本的にHTMLのDOM操作やAjax処理を簡単に記述する為のものなので、それ以外の処理(数値の足し算や配列データの操作)は、JavaScriptコードで記述する必要がある。
jQueryの使い方は、以下のようになる。

[app/views/js.erb ファイル]

$("#aaa");    # HTMLからidが[aaa]のDOMを取得する。
$(".aaa");      #HTMLからclassが[aaa]のDOMを取得する。
$("#aaa").html("こんにちは");     #先のように取得したDOMに対してメソッドを使う。

以下のように[app/views/js.erb]ファイルに$(function() {}を記載しない説明は、以下のようになる。

[app/views/bookmarks/create.js.erb]

$("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith("<%= j(render('boards/bookmark', board: @board)) %>");

htmlファイル内に直接jQueryを埋め込んで利用する場合は、scriptタグで囲って$(function() {}を記述しなければ、基本的に動かないが、 今回のようにjs.erbファイルにjQueryを記載する際は、functionを記載しなくても動くが、functionを記載した方が分かりやすくなり、意味不明なエラーなども回避できるので、js.erbファイルにもfunctionを記載した方が良い。($(function() {}によって、HTMLが読み込まれるのを待ってからjQueryが実行される。)

参考記事:

「Ruby on Railsで簡単で素早くWebアプリを開発する」 最終回 Rails + jQuery でAjaxを使ってみよう

ブックマークボタンのajax化 - olive_miuのブログ

【Rails】簡単なajax処理 (remote true) - bokuの学習記録

escape_javascriptメソッドって何ぞや。 - Qiita

今さら聞けない!jQueryとは【初心者向け】 | TechAcademyマガジン

JS形式のレスポンスと remote: true を使う - Qiita

jQuery 要素を置き換える(replaceWith/replaceAll) | ITSakura

railsで普通のリンクをajax通信に変更するテンプレートセット - Qiita

Railsで remote: true と js.erbを使って簡単にAjax(非同期通信)を実装しよう!(いいね機能のデモ付) - Qiita

Railsで remote: true と js.erbを使って簡単にAjax(非同期通信)を実装しよう!(いいね機能のデモ付) - Qiita

jquery — jQuery replaceWith()とhtml()の違いは何ですか?

【IT用語】 Ajaxとは?初心者向けに豊富な画像で仕組みを解説 | Pikawaka

【Rails】 remote: trueでフォーム送信をAjax実装する方法とは? | Pikawaka

Ajax(非同期通信)についてわかりやすさ重視でまとめてみた(Rails使用のデモ付) - Qiita

【Rails入門】ajaxの使い方まとめ | 侍エンジニアブログ

【Rails】 respond_toメソッドの使い方まとめ | Pikawaka

$(function(){})ってどういう意味?jQueryのおまじないをわかりやすく解説します – More Web

Railsで remote: true と js.erbを使って簡単にAjax(非同期通信)を実装しよう!(いいね機能のデモ付) - Qiita