ヨージとプログラミング

プログラミング勉強の記録

【Rails】フォロー機能をAjaxで実装する時は、フォロー後にユーザー情報を更新しよう

星を押してフォローすると星が塗りつぶされるタイプ

フォロー前

フォロー後

星を塗りつぶすかどうかは, current_userがすでにフォローしているかどうかをif文で確認して決めています。

- if current_user.following?(user)
  # 塗りつぶす
  = link_to icon('fas', 'star'), [リンク先], method: :delete, remote: true
- else
  # 塗りつぶさない
  = link_to icon('far', 'star'), [リンク先], method: :post, remote: true

これはパーシャルですが、if current_user.following?(user)でcurrent_userが引数のuserをフォローしているか確認し、星にはcontrollerへのリンクを付与しています。
このリンクを押すとコントローラーのcreateアクションもしくはdestroyアクションに送られ、followもしくはunfollowを行います。これをAjaxでページ更新をせずに行うため、リンクの末尾にremote: trueを付けています。
では、コントローラーの方を見てみましょう。
フォローするユーザーをUserモデルから取得して、フォローしたりアンフォローするだけのシンプルなものだと分かります。
Ajaxを用いますので、自動でjsが起動し新しい画面がレンダリングされます。

class RelationshipsController < ApplicationController

  def create
    # フォローするユーザーを取得
    @follow_user = User.find(params[:user_id])
    # フォロー
    current_user.follow(follow_user)
    # create.js.erbで新しい画面がrenderされる
  end

  def destroy
    # アンフォローするユーザーを取得
    @follow_user = current_user.active_relationships.find_by(follower_id: params[:user_id])
    # アンフォロー
    follow_user.destroy
    # destroy.js.erbでrender
  end
end

星の状態が更新されない…

星をクリックしても塗りつぶされることはありませんでした。
おかしい…、いろいろ確認し、jsによるレンダリング自体はきちんと行われていることはわかりました。
ということはレンダリングする内容に問題があるようです。

$("#follow-btn-<%= @follow_user.id %>").html("<%= j(render partial: 'users/follow', locals: { user: @follow_user }) %>");

html()の中身がレンダリングの内容です。@follow_userはコントローラーで受け取ったuserオブジェクトです。
実はこのコード自体に問題はありませんでした。

フォロー後にuserオブジェクトを再取得したら上手くいった

はい先程のコードです

# 修正前
class RelationshipsController < ApplicationController

  def create
    # フォローするユーザーを取得
    @follow_user = User.find(params[:user_id])
    # フォロー
    current_user.follow(follow_user)
    # create.js.erbで新しい画面がrenderされる
  end

  def destroy
    # アンフォローするユーザーを取得
    @follow_user = current_user.active_relationships.find_by(follower_id: params[:user_id])
    # アンフォロー
    follow_user.destroy
    # destroy.js.erbでrender
  end
end

createアクションもdestroyアクションも真っ先にユーザーを取得し、その後にフォローを行っています。そして、その後のjsでのレンダリングにはこの真っ先に取得したものを渡していました。
これをフォロー後に取得し直してみました。

# 修正後
class RelationshipsController < ApplicationController

  def create
    # フォローするユーザーを取得
    @follow_user = User.find(params[:user_id])
    # フォロー
    current_user.follow(follow_user)
    # フォロー後user情報更新
    @follow_user = User.find(params[:user_id])           # 追加
    # create.js.erbで新しい画面がrenderされる
  end

  def destroy
    # アンフォローするユーザーを取得
    @follow_user = current_user.active_relationships.find_by(follower_id: params[:user_id])
    # アンフォロー
    follow_user.destroy
    # アンフォロー後user情報更新
    @follow_user = User.find(params[:user_id])          # 追加
    # destroy.js.erbでrender
  end
end

上記のコードで無事、Ajaxでfollow機能をつけることができました。 なんとなく最新の情報を取得したからうまく行ったのかかと考えられますが、実際の中身がどうなっているとかは見てないので、時間がある時に見てみたいと思います。