【Ajax通信】いいね機能の非同期通信での実装

おはようございます。
今日はいいね機能の非同期通信での実装を書いていきたいと思います。今回は同期通信での実装はできているものとして書いていきますのでご承知ください。

前提

同期通信でのいいね機能の実装が済んでいる状態
(同期通信のいいね機能がまだできていないのであればまずはそちらを行うことを勧めます。)

実装の流れ

① 部分テンプレートの作成とオプション追加
② コントローラーでのページ遷移の記述削除
③ create.js.hamlとdestroy.js.hamlファイルを作成し、いいねボタン部のみviewを変更

① 部分テンプレートの作成とオプション追加

いいね機能を実装するにあたり、いいねボタン部分のviewを部分テンプレートに移します。なぜ移すかというといいねが押された際、当然viewを変更しないといけませんが、(いいねの数が変わるため)そのviewの変更を部分テンプレートを使って行います。そのため、いいねボタン部分を部分テンプレートで書く必要があります。
また、非同期通信を行うためのオプション(remote: true)をlink_toに付けます。

_like.html.haml

- if user_signed_in?
  - if set_list.liked_by?(current_user)
    = link_to event_set_list_likes_path(event, set_list), method: :delete, remote: true do
      .like__box
        .heart__mark__unregistered
          &#9829
        .like__number
          = set_list.likes.count
  - else
    = link_to event_set_list_likes_path(event, set_list), method: :post, remote: true do
      .like__box
        .heart__mark__registered
          &#9829
        .like__number
          = set_list.likes.count
- else
  .like__box
    .heart__mark__registered
      &#9829
    .like__number
      = set_list.likes.count

show.html.haml

略
.button__box
   .like__button
      = render partial: "likes/like", locals: { event: @event, set_list: @set_list }
   .twitter__box
      %i.fab.fa-twitter
略


remote: true

link_toにremote: trueの記述を加えることにより、非同期通信でコントローラーに値を送信してくれます。

render partial: "likes/like", locals: { event: @event, set_list: @set_list }

renderメソッドを使って部分テンプレートを呼び出します。
localsオプションの中身は@event = @eventのようにはできないので注意。(2時間返して(涙))


② コントローラーでのページ遷移の記述削除

非同期通信でページ遷移は行わないため、redirect_to ~~の記述は消します。代わりに部分テンプレートでの記載にeventやset_listのインスタンス変数が必要になってくるので、こちらを定義します。インスタンス変数の定義忘れがちなので、要注意です。(1日返して(涙))

likes_controller

class LikesController < ApplicationController
  def create
    @like = Like.create(set_list_id: params[:set_list_id], user_id: current_user.id)
    @set_list = SetList.find(params[:set_list_id])
    @event = Event.find(params[:event_id])
  end

  def destroy
    @like = Like.find_by(user_id: current_user.id, set_list_id: params[:set_list_id])
    @set_list = SetList.find(params[:set_list_id])
    @event = Event.find(params[:event_id])
    @like.destroy
  end
 end


③ create.js.hamlとdestroy.js.hamlファイルを作成し、いいねボタン部のみviewを変更

コントローラーでの処理を終えた後、createアクションの場合はcreate.js.hamlへdestroyアクションの場合はdestroy.js.hamlへ処理の権限が移ります。(これらはデフォルトではないので自分で作る必要有りです。)
そしてこれらファイルの中で部分テンプレートを使っていいねボタンのいいね数を更新してあげます。

create.js.haml

$(".like__button").html("#{escape_javascript(render partial: 'likes/like', locals: { event: @event, set_list: @set_list })}");

destroy.js.haml

$(".like__button").html("#{escape_javascript(render partial: "like", locals: { event: @event, set_list: @set_list })}");


html()メソッド

セレクタの中のHTML要素を引数のHTMLで置き換えます。

escape_javascript関数

公式のチュートリアルには「JavaScriptファイル内にHTMLを挿入するときに実行結果をエスケープする (画面に表示しない) ために必要です。」とありますが、意味がよく分かっていません。また、分かれば記事書きたいと思います。とりあえずJavaScriptでHTMLを挿入するときに必要になるという理解で問題ないと思います。



以上になります。
こうやってまとめてみると簡単なように見えますが、二箇所ハマった部分があったので個人的には苦労した印象です。コントローラーでのインスタンス変数の定義し忘れには十分注意して下さい(初心者丸出しすいません。汗)
ここまで読んでくださり、ありがとうございました。分かりにくいやアドバイス等ありましたらコメントくださると幸いです。では!