【rails】Ajaxを使ったフォローボタンの実装で躓いたところ


はじめに

初学者がポートフォリオ作成の際に躓いたことをメモします。
今回は躓いた部分だけ記載します。全体を知りたい方は下記のリンクがわかりやすいです。
https://railstutorial.jp/chapters/following_users?version=4.2#sec-a_working_follow_button_the_standard_way
https://qiita.com/Kaisyou/items/e918b77465e3f55c97a2

Ajaxとは

『Ajaxとは、あるWebページを表示した状態のまま、別のページや再読込などを伴わずにWebサーバ側と通信を行い、動的に表示内容を変更する手法。ページ上でプログラムを実行できるプログラミング言語JavaScriptの拡張機能を用いる。』

簡単に言うと、『javascriptによって必要な部分だけを更新する技術。その為ページ全体を再読み込みする必要がなく、素早いレスポンスが可能になる』と言ったところでしょうか?

前提

今回はユーザー一覧画面(users/index)でフォローボタンを表示します。

users_controller.rb
def index
    @q = User.ransack(params[:q])
    @users = @q.result(distinct: true)
  end
users/index.slim
- @users.each do |user| 
# (中略)
  == render "follow_form" , object: @user if logged_in?
users/_follow_form.slim
- unless current_user?(object) 
  div id="follow_form_#{object.id}"  #フォロー一覧画面でボタンを表示させる際にuserを区別する為に動的にしている
    - if current_user.following?(object) 
      = render 'unfollow' , object: object
    - else 
      = render 'follow' , object: object
users/_follow.slim
= form_with(model: current_user.active_relationships.build) do |f| 
 = hidden_field_tag :followed_id, object.id 
 = f.submit "Follow", class: "btn btn-primary" 

躓いたところ(1) relationships_controller.rb内のrespond_toについて

他の記事を見るとrespond_toを使っている場合が多かったが内容が理解出来なかった。
respond_toについて以下のリンクがわかりやすかった。
https://www.javadrive.jp/rails/controller/index7.html#section3

送られてくるリクエストの形式によって処理を分ける。リクエストがHTML形式で送られてきた場合とjs形式で送られてきた場合で処理を分けている。

relationships_controller.rb
class RelationshipsController < ApplicationController
before_action :logged_in_user

  def create
    @user = User.find(params[:followed_id])
    current_user.follow(@user)
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end

  def destroy
    @user = Relationship.find(params[:id]).followed
    current_user.unfollow(@user)
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end

end



しかし今回はform_withでremote:trueを設定している為、HTML形式でリクエストが送られることはないので以下のようにした。

relationships_controller.rb
class RelationshipsController < ApplicationController
before_action :logged_in_user

  def create
    @user = User.find(params[:followed_id])
    current_user.follow(@user)
  end

  def destroy
    @user = Relationship.find(params[:id]).followed
    current_user.unfollow(@user)
  end

end

remote:trueを設定している為、JS形式のリクエストが送られる。デフォルトでアクション名と同じ名前のjsファイルが呼ばれる。
( createアクションの場合: app/views/relationships/create.js.erb )


躓いたところ(2) create.js.erb内の"#follow_form_<%= @user.id %>

JQueryのコードの理解が足りずバグが発生した。users/show画面では#follow_formで良いが、ユーザー 一覧画面の場合ユーザー を区別しなければならない為、idを動的に変更する必要がある。

views/relationships/create.js.erb
$("#follow_form_<%= @user.id %>").html("<%= j(render 'users/unfollow', object: @user) %>"); 
$("#followers").html('<%= @user.followers.count %>');  #ユーザー一覧画面では使わない(フォロワーの数を表示しない為)

上記のコードはJQueryで書かれており、htmlメソッドは指定した要素を書き換えることができる。

htmlメソッドについて https://www.sejuku.net/blog/38267

一行目でusers/showの#follow_form<%= @user.id %>の内容をusers/unfollowに置き換えている。また@userusers/unfollow内でobjectとして参照している。

最後に

誰かのお役にたてれば幸いです。
間違えている部分があればコメントお願いいたします。