【Rails】簡単なAjax(非同期通信)を実装する

いいね機能を例に簡単にAjax機能を追加してみます。

Ajaxの概要

サーバーと通信したときに、ページ遷移を行わず指定した一部分だけを変更する処理のこと

何らかのボタン等を押して、リクエストを送ったときに

本来ならば設定したerbやhamlレンダリングする動作を

設定したjs.erbを呼び出し、それに応じて指定した部分のhtmlを書き換えるといった処理を実現できる。

準備編

jqueryを使用するためGemをインストールする。

gem 'jquery-rails'
$ bundle install

application.jsに下記を記載。

//= require jquery
//= require rails-ujs

ちなみにRails5.1より前の場合は

//= require jquery
//= require jquery-ujs

となる。

View編

まずはボタンの部分テンプレートから。

_sub_button.html.erb

<% if current_user.checksub?(id) %>
  <% book = Book.find_by(id: id) %>
  <%= form_with(model: current_user.subscribes.find_by(book_id: current_user.books.find_by(id: book.id), method: :delete) do |f| %>
    <%= hidden_field_tag :id, id %>
    <%= f.submit '登録済みです', class: 'btn btn-info w-100 mt-1 mb-1' %>
  <% end %>
<% else %>
  <%= form_with(model: current_user.subscribes.build) do |f| %>
    <%= hidden_field_tag :id, id %>
    <%= f.submit '登録する', class: 'btn btn-outline-info w-100 mt-1 mb-1' %>
  <% end %>
<% end %>

ぶっちゃけ、既に完成している場合は変更点はないと思う。

ただ注意してほしいのがAjaxを使う場合、formタグにremote: trueを入れる必要がある。

といっても上記のようにform_withを使用している場合はデフォルトでremote: trueとなっているので、書く必要はない。

(form_forやform_tagを使っている場合はそうではないのでremote: trueを記載しましょう。)

逆にform_withのデフォルトであるremote: trueをオフにする場合はlocal: trueと追加する。

参考:https://qiita.com/kamelo151515/items/e7c2225dc19936a31756

次は上の部分テンプレートを呼び出している箇所

_card.html.erb

<div id="subscribe_book_zone_<%= book.id %>">
  <%= render 'subscribes/sub_button', id: book.id %>
</div>

これをbook.idなど特定できるものを使ってidを指定してあげる。

あとでjqueryで変更箇所を指定するときに使う。
当たり前だが、classで指定してあげると、クリックしたときに変化する対象を複数にできるので頭の隅に入れておく。

Controller編

ボタンの登録/解除の処理を書いてあるコントローラーへ。

subscribes_controller.rb

def create
    @book = Book.find(params[:id])
    # ~いろんな処理~
    current_user.addsub(@book)
end

既に普通のボタンを作った場合はあまり変更点はない。

redirect_back(fallback_location: root_url)

などがあれば必要なくなるので消すこと。destroyも普通通りで良い。

上記でいう@bookなどのボタンの対象となるモデルは次のjqueryで使用するので、確認すること。

js.erb編

まずファイルを手動で作成する。

app/views/コントローラー名/アクション名.js.erb

として作成する。

今回の例だとボタンのcreateとdestroyなので

create.js.erb

destroy.js.erb

の2つのファイルを作成することになる。

$("#subscribe_book_zone_<%= @book.id %>").html("<%= j(render partial: 'sub_button', locals: { isbn: @book.isbn }) %>");

内容は2つとも上記のように。

説明

$("#subscribe_book_zone_<%= @book.id %>")

View編の部分テンプレートを呼び出している部分を囲ったidを呼び出している。

これでボタンを押したとき、どこを押したのか場所がわかる。

.html("<%= j(render partial: 'sub_button', locals: { isbn: @book.isbn }) %>");

.htmlを使ってhtmlの書き換えを行う。

renderを使ってボタンの部分テンプレートを指定、

localsで変数を渡している。

j()で囲っているのはエスケープ。

参考

qiita.com

qiita.com