質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

1100閲覧

【Rails】リロードしないとフォローボタンが切り替わらない

punchan36

総合スコア105

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2020/02/23 22:27

編集2020/02/26 08:41

前提・実現したいこと

Ruby on Railsでユーザー同士のフォロー機能を作っています。
こちらのサイト等を参照しました。
Ruby on Rails ~フォロー(友達申請)機能の実装(コードメモ)

上手く機能しているのですが、フォロー・アンフォローボタンがリロードをしないと切り替わりません。
「remote: true」を適用しており、フォローしているユーザー数は瞬時に切り替わってくれます。ボタンも、フォローしているならアンフォローボタンを、フォローしていないならフォローボタンに瞬時に切り替わって欲しいです。
どなたかお知恵を拝借頂けると幸いです。

※数分前に同じ質問を投稿しましたが、書いた文章がほぼ消えた状態で送信されてしまいました。申し訳ありません。

該当のソースコード(show.html.erb)

Ruby

1<div class="main user-show"> 2 <div class="container"> 3 <div class="user"> 4 <img class="cover_photo" src="<%= "/user_cover_images/#{@user.cover_image_name}" %>"> 5 <img class="photo" src="<%= "/user_images/#{@user.image_name}" %>"> 6 </div> 7 8 <div class="tab-container"> 9 <!--タブ--> 10 <ul class="tab-group"> 11 <li class="tab is-active">Bio</li> 12 <li class="tab"><%= (@user.name + "'s organized events") %></li> 13 <li class="tab">Schedule</li> 14 </ul> 15 16 <!--タブを切り替えて表示するコンテンツ--> 17 <div class="panel-group"> 18 <div class="panel is-show">Content-A</div> 19 20 <div class="panel"> 21 <% @user.posts.each do |post| %> 22 <div class="posts-index-item"> 23 <div class="post-left"> 24 <img src="<%= "/user_images/#{post.user.image_name}" %>"> 25 </div> 26 <div class="post-right"> 27 <div class="post-user-name"> 28 <%= link_to(post.user.name, "/users/#{post.user.id}") %> 29 </div> 30 <%= link_to(post.title, "/posts/#{post.id}") %> 31 </div> 32 </div> 33 <% end %> 34 </div> 35 36 <div class="panel"> 37 <% @likes.each do |like| %> 38 <% post = Post.find_by(id: like.post_id) %> 39 <div class="posts-index-item"> 40 <div class="post-left"> 41 <img src="<%= "/user_images/#{post.user.image_name}" %>"> 42 </div> 43 <div class="post-right"> 44 <div class="post-user-name"> 45 <%= link_to(post.user.name, "/users/#{post.user.id}") %> 46 </div> 47 <%= link_to(post.title, "/posts/#{post.id}") %> 48 </div> 49 </div> 50 <% end %> 51 </div> 52 </div> 53 </div> 54 55 <% if @user.id == @current_user.id %> 56 57 <% else %> 58 <% if @isRoom == true %> 59 <p><a href="/rooms/<%= @roomId %>">チャットへ</a> 60 <% else %> 61 <%= form_for @room do |f| %> 62 <%= fields_for @entry do |e| %> 63 <%= e.hidden_field :user_id, :value=> @user.id %> 64 <% end %> 65 <%= f.submit "チャットを始める" %> 66 <% end %> 67 <% end %> 68 <% end %> 69 70 <h2><%= @user.name %></h2> 71 <% if @user.id == @current_user.id %> 72 <%= link_to("編集", "/users/#{@user.id}/edit") %> 73 <%= link_to("削除", "/users/#{@user.id}/destroy", {method: :post, data: {confirm: "Are you sure to delete your account?"}, class: "link"}) %> 74 <% end %> 75 76 <div id="follow-btn"> 77 <%= render 'users/follow_form' %> 78 </div> 79 <h4> 80 <%= render 'users/stats' %> 81 </h4> 82 83 </div> 84</div>

該当のソースコード(_follow_form.html.erb)

Ruby

1<% unless @current_user.id == @user.id %> 2 <% if @current_user.following?(@user) %> 3 <%= render 'users/unfollow', user: @user %> 4 <% else %> 5 <%= render 'users/follow', user: @user %> 6 <% end %> 7<% end %>

該当のソースコード(_follow.html.erb)

Ruby

1<%= form_for(@current_user.following_relationships.build(following_id: @user.id), 2 remote: true) do |f| %> 3 <div><%= f.hidden_field :following_id %></div> 4 <%= f.submit "Follow", class: "btn btn-large btn-primary" %> 5<% end %>

該当のソースコード(_unfollow.html.erb)

Ruby

1<%= form_for(@current_user.following_relationships.find_by(following_id: @user.id), 2 html: { method: :delete }, 3 remote: true) do |f| %> 4 <%= f.submit "Unfollow", class: "btn btn-large" %> 5<% end %>

該当のソースコード(relationships.controller.rb)

Ruby

1class RelationshipsController < ApplicationController 2 def create 3 @user = User.find(params[:relationship][:following_id]) 4 @current_user.follow!(@user) 5 respond_to do |format| 6 format.html { redirect_to @user } 7 format.js 8 end 9 end 10 11 def destroy 12 @user = Relationship.find(params[:id]).following 13 @current_user.unfollow!(@user) 14 respond_to do |format| 15 format.html { redirect_to @user } 16 format.js 17 end 18 end 19end

該当のソースコード(users_controller.rb)

Ruby

1class UsersController < ApplicationController 2 before_action :authenticate_user, {only: [:index, :show, :edit, :update]} 3 before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]} 4 before_action :ensure_correct_user, {only: [:edit, :update]} 5 6 def index 7 @users = User.all.order(created_at: :desc) 8 end 9 10 def show 11 @user = User.find_by(id: params[:id]) 12 @likes = Like.where(user_id: @user.id) 13 @currentUserEntry=Entry.where(user_id: @current_user.id) 14 @userEntry=Entry.where(user_id: @user.id) 15 if @user.id == @current_user.id 16 else 17 @currentUserEntry.each do |cu| 18 @userEntry.each do |u| 19 if cu.room_id == u.room_id then 20 @isRoom = true 21 @roomId = cu.room_id 22 end 23 end 24 end 25 if @isRoom 26 else 27 @room = Room.new 28 @entry = Entry.new 29 end 30 end 31 end 32 33 def follow 34 @user = User.find_by(id: params[:id]) 35 end 36 37 def new 38 @user = User.new 39 end 40 41 def create 42 @user = User.new( 43 name: params[:name], 44 email: params[:email], 45 image_name: "default_user.jpg", 46 cover_image_name: "default_cover_user.jpg", 47 password: params[:password] 48 ) 49 if @user.save 50 session[:user_id] = @user.id 51 flash[:notice] = "ユーザー登録が完了しました" 52 redirect_to("/users/#{@user.id}") 53 else 54 render("users/new") 55 end 56 end 57 58 def edit 59 @user = User.find_by(id: params[:id]) 60 end 61 62 def update 63 @user = User.find_by(id: params[:id]) 64 @user.name = params[:name] 65 @user.email = params[:email] 66 if params[:image] 67 @user.image_name = "#{@user.id}.jpg" 68 image = params[:image] 69 File.binwrite("public/user_images/#{@user.image_name}", image.read) 70 end 71 if params[:cover_image] 72 @user.cover_image_name = "#{@user.id}_cover.jpg" 73 cover_image = params[:cover_image] 74 File.binwrite("public/user_cover_images/#{@user.cover_image_name}", cover_image.read) 75 end 76 if @user.save 77 flash[:notice] = "ユーザー情報を編集しました" 78 redirect_to("/users/#{@user.id}") 79 else 80 render("users/edit") 81 end 82 end 83 84 def destroy 85 @user = User.find_by(id: params[:id]) 86 @user.destroy 87 flash[:notice] = "アカウントを削除しました" 88 redirect_to("/posts/index") 89 end 90 91 def login_form 92 end 93 94 def login 95 @user = User.find_by(email: params[:email]) 96 if @user && @user.authenticate(params[:password]) 97 session[:user_id] = @user.id 98 flash[:notice] = "ログインしました" 99 redirect_to("/posts/index") 100 else 101 @error_message = "メールアドレスまたはパスワードが間違っています" 102 @email = params[:email] 103 @password = params[:password] 104 render("users/login_form") 105 end 106 end 107 108 def logout 109 session[:user_id] = nil 110 flash[:notice] = "ログアウトしました" 111 redirect_to("/login") 112 end 113 114 def likes 115 @user = User.find_by(id: params[:id]) 116 @likes = Like.where(user_id: @user.id) 117 end 118 119 def ensure_correct_user 120 if @current_user.id != params[:id].to_i 121 flash[:notice] = "権限がありません" 122 redirect_to("/posts/index") 123 end 124 end 125 126 def top 127 @user = User.find_by(id: params[:id]) 128 @likes = Like.where(user_id: @current_user.id) 129 end 130 131 def following 132 @title = "フォロー" 133 @user = User.find(params[:id]) 134 @users = @user.followings 135 render 'show_follow' 136 end 137 138 def followers 139 @title = "フォロワー" 140 @user = User.find(params[:id]) 141 @users = @user.followers 142 render 'show_follow' 143 end 144 145end

該当のソースコード(relationships#create.js.erb)

Ruby

1$("#user_<%= @user.id %>").html("<%= escape_javascript(render('users/follow_form', user: @user)) %>") 2$("#followers").html('<%= @user.followers.count %>')

該当のソースコード(relationships#destroy.js.erb)

Ruby

1$("#user_<%= @user.id %>").html("<%= escape_javascript(render('users/follow_form', user: @user)) %>") 2$("#followers").html('<%= @user.followers.count %>')

該当のソースコード(index.js.erb)

javascript

1$("#follow-btn").html("<%= escape_javascript(render partial: 'users/follow_form' %>")

試したこと

最近jQueryを用いページ内タブを実装したのですが、その際にもリロードをしないとタブの内容が切り替わらない事象が発生しました。そこでは「Turbolinks」の設定を変えるなどして解決しましたが、今回のフォローボタンではjQueryも使用していない為、解決策が分からず困っています。

補足情報(FW/ツールのバージョンなど)

ruby 2.6.4p104
RubyGems 3.0.3
Rails 5.2.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

コントローラーの中身を見ていないので推測でしかないのですが、フォローボタンorアンフォローボタンを押した時、「ユーザーをフォローする処理」と「jQueryでフォローしているユーザー数を書き換える処理」が走っているような気がします。

「フォローボタンを押した時の処理」に「jQuery側でアンフォローボタンを表示する」、「アンフォローボタンを押した時の処理」に「jQuery側でフォローボタンを表示する」コードを追加してあげれば、やりたかったことが実現できるのではないかなと思います。

remote: true を使うと、ページを更新せずリクエストだけ投げてくれるようになります。

リクエストを送ってもHTMLの中身はそのままなので、フォローボタンの表示は変わりません。リロードせずにHTMLの中身を変更したい場合は、jQuery側で書き換えてあげる必要があります。

- - - - - - ↓ 以下追記です ↓ - - - - - - -

Ajaxのリクエストについてですが、コントローラーの下記部分に記載があります。

ruby

1class RelationshipsController < ApplicationController 2 def create 3 @user = User.find(params[:relationship][:following_id]) 4 @current_user.follow!(@user) 5 respond_to do |format| 6 format.html { redirect_to @user } 7 format.js # ← ★★★ この部分 ★★★ 8 end 9 end

Relationshipsのcreateアクションでは app/views/relationships/create.js.erb が、
Relationshipsのdestroyアクションでは app/views/relationships/destroy.js.erb が呼ばれます。

→ index.js.erbにフォローボタンの処理を書いても、それを呼び出す記述がないので動きません。

(参考サイトも拝見しましたが、そちらではコントローラーのcreateアクションとdestroyアクションの中でindex.js.erbを呼び出しているようです)

今回の場合であれば、フォローボタンの処理だけをindex.js.erbに分けて書くのではなく、「createアクションで動かす処理はcreate.js.erb」 「destroyアクションで動かす処理はdestroy.js.erb」に書いた方が分かりやすいのではないかと思います。

→ index.js.erbに書いたような処理を、すでに作成している create.js.erbdestroy.js.erbに記載すると良いのではないでしょうか…?

【 参考ページ 】 Rails で JavaScript を使用する - Railsガイド

  • 「4.1 シンプルな例」 の辺り

投稿2020/02/25 00:36

編集2020/02/26 10:17
kyoruni

総合スコア93

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

punchan36

2020/02/26 08:48

ご回答有難うございます!関係がありそうなコントローラを追加表示しました。 HTMLの中身は別で処理しないと、リロードなしでは変わらないと言う事を知りませんでした…。 非同期処理について以下のサイト等で勉強し「js.erb」も追加してみましたが、まだリロードしないと動いてくれません。 https://whatsupguys.net/programming-school-dive-into-code-learning-82/ いくつかコードを追加表示しましたので、間違いがありましたらご指摘頂けると有難いです!
kyoruni

2020/02/26 10:15

内容の追記ありがとうございます 回答の方に色々追記しました!
punchan36

2020/02/27 11:32

ご回答有難うございます! 以下の1行を「create.js.erb」、「destroy.js.erb」に加える事で無事解決致しました。 $("#follow-btn").html("<%= escape_javascript(render('users/follow_form', user: @user )) %>") 以前ネットで参考にした「respond_to」内の記述等を、完全に理解する前に実装してしまったツケが回った形となりました…。 ここまで詳しく教えて下さり、本当に恥ずかしいやら有難いやらですが… 今後もっと勉強していきます。有難うございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問