技術系ブログ

とにかく小ネタで

【rails】いいね機能 非同期編

やっとできたので書いていきます。

↓前回まで
【rails】いいね機能実装 (追記あり) - 技術系ブログ

参考: 第14章 ユーザーをフォローする - Railsチュートリアル

[https://qiita.com/tambo/items/45211df065e0c037d032:title]

【Rails初心者】Ajaxの実装方法を理解する(非同期通信) - Qiita

導入手順

jqueryを使えるようにします。
②remote: true 追加
③.js.erbファイル作成
④コントローラー側編集です。

そもそも非同期通信とは、

参考:非同期処理:コールバック/Promise/Async Function · JavaScript Primer #jsprimer
初心者目線でAjaxの説明 - Qiita  

その前に同期通信は 同期処理ではコードを順番に処理していき、ひとつの処理が終わるまで次の処理は行いません。
同期処理では実行している処理はひとつだけとなるため、とても直感的な動作となります。
つまり、 同期処理ではひとつの処理が終わるまで、次の処理へ進むことができない。

非同期通信は、ひとつの非同期処理が終わるのを待たずに次の処理を評価します。
つまり、非同期処理では同時に実行している処理が複数あります。

一部分のみの更新とう言う感じですかね。

Ajaxとは

Asynchronous JavaScript + XML (AJAX) はそれ自体がある種の技術というわけではありませんが、
Jesse James Garrett によって 2005 年に作られた言葉で、既存の技術同士を組み合わせた新しいアプローチを意味します。
Ajax - Wikipedia

準備

jqueryを使えるようにします。
gem 'jquery-rails'

#app/asssets/javascripts/application.js
-# バージョンがRails5.1以降の場合
//= require jquery
//= require rails-ujs

-# Rails5.1より前の場合
//= require jquery
//= require jquery-ujs

view側

#app/views/likes/_like.html.slim

-if current_user.likes.find_by(post_id: @post.id)
  #liked
    = link_to post_like_path(@post, current_user.likes.find_by(post_id: @post.id)), method: :delete, remote: true do
      p いいね済
- else
  #likable
    = link_to post_likes_path(@post,current_user.likes.build),method: :post, remote: true do
      p いいね

(@post, current_user.likes.find_by(post_id: @post.id)),(@post,current_user.likes.build) のように書いてアクション側にidを送ります。非同期導入前の段階では書かなくてもエラーが出ませんでしたが、 非同期通信をする際には必要なようです。
またremote: trueそれぞれにidを追加しています
idを追加するとこで、jqueryセレクタとして特定することができます。

remote: trueとは

参考:Rails で JavaScript を使用する - Railsガイド

フォームの送信がブラウザによる通常の送信メカニズムではなくAjaxによって送信されるようになります。 追加するだけでAjaxが使えるようになると考えてください。
そして、リクエストがhtml形式からjs形式になります。 つまり.jsファイルを探すようになります。 詳しく説明すると、link_to post_like_path(@post)ではhtml形式なら
controllerは「app/views/controller名/アクション名.リクエストの形式.erb」というファイルを探しに行きます。
しかし、今回のpostリクエストでいうと、html形式だとapp/views/likes/create.html.slimを探しますが,
js形式だとapp/views/likes/create.js.erbを読み込みます。

.js.erbファイルを作成

.js.erbファイルの作成にはファイル名を注意してください
link_to先のアクション名に合わせてください。 app/views/controller名/アクション名.js.erbで作成します。
今回は、createdestroy2つ作ります。 touch app/views/likes/create.js.erb
touch app/views/likes/destroy.js.erb

#app/views/likes/create.js.erb

$("#likable").html("<%= escape_javascript(render('likes/like')) %>");
#app/views/likes/destroy.js.erb
$("#liked").html("<%= escape_javascript(render('likes/like')) %>");

escape_javascriptメソッドは、JavaScriptファイル内にHTMLを挿入するときに実行結果をエスケープするために必要です。

コントローラー側

下記をcreate,destroyアクションにそれぞれ追加します。

    respond_to do |format|
      format.html { redirect_to @post }
      format.js
    end

respond_toメソッドとは、
上の (ブロック内の) コードのうち、いずれかの1行が実行されます。

#app/controllers/likes_controller.rb
class LikesController < ApplicationController
  before_action :set_post, only: [:create, :destroy]
  def create
    @like = current_user.likes.create(like_params)

    respond_to do |format|
      format.html { redirect_to @post }
      format.js
    end
  end

  def destroy
    @like = Like.find_by(like_params, user_id: current_user.id)
    @like.destroy
    respond_to do |format|
      format.html { redirect_to @post }
      format.js
    end
  end

  private
  def set_post
    @post = Post.find(params[:post_id])
  end
  def like_params
    params.permit(:post_id)
  end
end

おしまい。