【Rails】簡単なAjax(非同期通信)を実装する
いいね機能を例に簡単にAjax機能を追加してみます。
Ajaxの概要
サーバーと通信したときに、ページ遷移を行わず指定した一部分だけを変更する処理のこと。
何らかのボタン等を押して、リクエストを送ったときに
設定した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()で囲っているのはエスケープ。