実現したいこと
RailsでAjaxを用いて、いいね機能を実現しようと実装中です。
Twitterクローンのようなアプリを作成中です。
投稿一覧画面があり、各投稿に表示されるいいねボタンをユーザが押すことで、
いいねをすることができます。
言わずもがなかもしれませんが、具体的には下記の処理になります。
- いいね追加:いいねボタン(白抜きのハート)を押すと、Ajax処理により、
いいねボタンが黒塗りのハートへと表示が変わり、いいね数が1つ増加する。 - いいね取消:いいねボタン(黒塗りのハート)を押すと、Ajax処理により、
いいねボタンが白抜きのハートへと表示が変わり、いいね数が1つ減少する。
現状(上手くいっていない箇所、操作と結果)
上記「1.」「2.」のいいね追加・取消ともに実装し、正常に動作することを確認しました。
しかし、一点不具合を見つけてしまいました。
具体的には下記の操作を行った際に起こります。
「いいね数が1以上の投稿に対し、白抜きハートのいいねボタンをクリックし、いいね追加を行う」→「その後、いいねが2以上になった投稿に対し、黒塗りのハートのいいねボタンをクリックし、いいね取消を行う」
この操作の想定結果と、実際に今起こってしまった結果は以下の通りです。
想定していた結果(実現したい結果)
いいねが取り消され、いいね数が1つ減少し、いいねボタンが白抜きに変わる。
→この後、白抜きとなっているいいねボタンを押すと、再びいいね追加処理が行える。
今起こってしまった結果
いいねが取り消され、いいね数が1つ減少するが、いいねボタンは黒塗りのハートのままとなる。
→この後、黒塗りのハートボタンを押すと、いいね取消処理が実行され、いいね数が1つ減少する。
→いいね数が0になるまで取消処理を行うことができてしまう。いいね数が0になると、ようやくいいねボタンが白抜きのハートに戻り、いいね追加処理が行えるようになる。
(問題点:いいね取消時は1つしかいいね数を減少させられないはずなのに、いいね数が0になるまでいいね取消が行えてしまう)
起こってしまった結果(不具合)現象のキャプチャ
②白抜きハートのいいねボタンをクリックし、いいね追加を行う。
③その後、いいねが2以上になった投稿に対し、黒塗りのハートのいいねボタンをクリックし、いいね取消を行う(いいね数が1つ減少するが、いいねボタンは黒塗りのハートのままとなる)※問題点
④いいね数が0になるまで取消処理を行うことができてしまう。※問題点
⑤いいね数が0になると、ようやくいいねボタンが白抜きのハートに戻り、いいね追加処理が行えるようになる
schema.rb ※いいねデータのみ
ruby
1 create_table "likes", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t| 2 t.integer "user_id", null: false 3 t.integer "post_id", null: false 4 t.datetime "created_at", null: false 5 t.datetime "updated_at", null: false 6 t.index ["post_id"], name: "index_likes_on_post_id" 7 t.index ["user_id", "post_id"], name: "index_likes_on_user_id_and_post_id", unique: true 8 t.index ["user_id"], name: "index_likes_on_user_id" 9 end
routes.rb ※いいねの箇所のみ
ruby
1 resources :posts do 2 resources :likes, only: %i[create destroy] 3 resources :comments, only: %i[create destroy] 4 end
likes_controller.rb
ruby
1class LikesController < ApplicationController 2 before_action :authenticate_user! 3 before_action :set_post, only: [:create, :destroy] 4 5 def create 6 @like = current_user.likes.create(like_params) 7 @post = Post.find(params[:post_id]) 8 end 9 10 def destroy 11 @like = Like.find_by(like_params, user_id: current_user.id) 12 @like.destroy 13 @post = Post.find(params[:post_id]) 14 end 15 16 private 17 def set_post 18 @post = Post.find(params[:post_id]) 19 end 20 21 def like_params 22 params.permit(:post_id) 23 end 24
→@like.destroyの箇所ですが、いいね取消処理実行時、railsのログを見ると、
DELETE文が対象のいいねデータのIDに対して実行され、正常終了し、最後にCOMMITもされていました。(このDELETE文のログは、いいね数が3から0まで減少させる際に毎回起こっていました)
→DELETEが動いていないわけでもないようです。
create.js.erbとdestroy.js.erb(同じ内容)
ruby
1$(".like_btn-<%= @post.id %>").html("<%= escape_javascript(render "shared/like", post: @post) %>");
post.rb (モデル(投稿))
ruby
1class Post < ApplicationRecord 2 belongs_to :user 3 has_many :likes, dependent: :destroy 4end
like.rb (モデル(いいね))※関連箇所のみ
ruby
1class Like < ApplicationRecord 2 belongs_to :user 3 belongs_to :post, counter_cache: :likes_count 4 validates :user_id, presence: true 5 validates :post_id, presence: true 6end
index.html.erb (投稿一覧画面)※いいねボタンの箇所のみ
ruby
1<% @posts.each do |post| %> 2 <tr class="post-<%= post.id %>"> 3 <td><%= link_to post.user.username, user_path(post.user_id) %></td> 4 <td><%= link_to post.title, post_path(post) %></td> 5 <td><%= render partial: 'shared/like', locals: {post: post} %></td>
_like.html.erb (いいねボタンの表示切替を行っている箇所)
ruby
1<div class="like_btn-<%= post.id %>"> 2<% if user_signed_in? %> 3 # いいねボタンの表示切替 4 <% like = Like.find_by(user_id: current_user.id ,post_id: post.id) %> 5 <% if like != nil %> 6 <%= link_to post_like_path(post, like), method: :delete, remote: true do %> 7 <i class="fas fa-heart"></i> 8 <% end %> 9 <% else %> 10 <%= link_to post_likes_path(post), method: :post, remote: true do %> 11 <i class="far fa-heart"></i> 12 <% end %> 13 <% end %> 14 <span> 15 # いいね数の表示 16 <%= post.likes_count %> 17 </span> 18<% else %> 19 # ログインしていない時はいいねマークといいね数のみ表示 20 <i class="fas fa-heart"></i> 21 <span> 22 <%= post.likes_count %> 23 </span> 24<% end %> 25</div>
→いいねボタンが白抜きか黒塗りかの判定は、
like = Like.find_by(user_id: current_user.id ,post_id: post.id) で、
操作中のユーザが、その投稿に対していいね済かどうかを抽出し、
if like != nil で判定を実施しています。
いいね取消処理実行時のサーバーログ
いいねボタンの表示判定時、
Like.find_by(user_id: current_user.id ,post_id: post.id)でいいねデータを取得できているはずなのに、正しく判定できていないようです。(いいね数は正確に集計できている)
Rails cでLike.find_byでデータ取得すると、いいね取消処理実行後はnilが取得できるのに、
画面でのif文判定時はnilが返らないのが、なぜかわかっておりません。(Ajaxに起因するものかと推測して、調査中です)
処理とデータの流れを一つ一つ追っていったり、
Ajaxでの取消処理実行時の注意事項なども調査中ではありますが、
並行して皆様にお力添えいただきたい次第です。
<バージョン>
ruby:2.6.5
rails:5.2.4.3
開発環境:Docker version 19.03.1
不足情報等ございましたら、ご指摘いただいたけますと幸いです。
よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー