2021/01/09 ブックマークボタンのajax化
ajaxとは
「Asynchronous JavaScript + XML」の略
Asynchronous →非同期の
JavaScript + XMLを使って非同期の通信を行うこと
通常はリクエストを送信すると、全ての情報を通信してレスポンスが戻ってくる。
ajaxの通信ではリクエストにたいしてレスポンスが戻ってくる(サーバーが処理している)間にも他の作業を行うことができる。
また、ページの一部のみリクエストして更新することができる。
railsにおいてはリクエストのなかで「remote: true」にすることで実装できる。
remoteオプション
<%= link_to 'tests#indexへリンク', ○○(tests#indexへのパス), local: true %>
とすると、対応するviewであるindex.html.erbに遷移する
<%= link_to 'tests#indexへリンク', ○○(tests#indexへのパス), remote: true %>
とすると、レンダリング先がjsファイルになる。
indexアクションを通過した後、index.html.erbではなく、index.js.erbファイルに向かうことになる。
そして拡張子が「js.erb」となっているこのファイル内にはjsの処理+rubyの記述を用いることができる。
js.erbファイルの作成
create、destroyアクションに対するテンプレートをそれぞれ作成
#create.js.erb document.getElementById("js-bookmark-button-for-board-#{board.id}").innerHTML = '<%= j(render 'unbookmark', board: board) %>' #destroy.js.erb document.getElementById("js-bookmark-button-for-board-#{board.id}").innerHTML = '<%= j(render 'bookmark', board: board) %>'
このCSS idのcreateアクションが実行されたときに、unbookmarkのテンプレートをレンダリングする
CSS idはbookmarkのパーシャルからコピペしてきたけどうまく動かない・・
undefined local variable or method `board' というエラーになるので、テンプレートを見直してみる
まず一つ目の#{board.id}は埋め込みrubyでの記載になるので<%= board.id %>に変更
これでもうまく動かず同じエラー。
テンプレートでローカル変数を使ってるので動かないのでは?と思い、コントローラ側をインスタント変数に変更し、テンプレートも変更
class BookmarksController < ApplicationController 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 end
document.getElementById("js-bookmark-button-for-board-<%= @board.id %>").innerHTML = '<%= j(render 'unbookmark', board: @board) %>'
元々のbookmarkパーシャルはパーシャル元から渡すときにlocal変数にしているが、js.erbで参照するのはアクションの変数のためインスタンス変数に変更が必要と理解
これでうまくいった!わけ分からなかった・・
と思いきや今度はCSS idが重複してしまうエラー
#create.js.erb document.getElementById("js-bookmark-button-for-board-#{board.id}").innerHTML = '<%= j(render 'unbookmark', board: board) %>'
これだと指定したidのHTMLの中身を入れ替えることになり、その入れ替え先にも同じidがあるのでidが重複することになってしまう
調べてみるとjqueryというやつで簡単にできそうなので書き換え
$("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith('<%= j(render 'unbookmark', board: @board) %>');
これで動くようになった
jqueryとか全然わかってないけど、とりあえずどんな役割で何をするためのものなのかがなんとなく理解できたのでよしとする