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

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

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

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

Ruby on Rails

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

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

Q&A

解決済

1回答

1242閲覧

【Rails】いいね機能:いいねを取り消す際、いいね数が0になるまで減少できてしまう

otdsh9432

総合スコア55

Ruby

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

Ruby on Rails

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

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

0グッド

1クリップ

投稿2020/06/02 14:16

編集2020/06/02 14:30

実現したいこと

RailsでAjaxを用いて、いいね機能を実現しようと実装中です。
Twitterクローンのようなアプリを作成中です。
投稿一覧画面があり、各投稿に表示されるいいねボタンをユーザが押すことで、
いいねをすることができます。
言わずもがなかもしれませんが、具体的には下記の処理になります。

  1. いいね追加:いいねボタン(白抜きのハート)を押すと、Ajax処理により、
    いいねボタンが黒塗りのハートへと表示が変わり、いいね数が1つ増加する。
  2. いいね取消:いいねボタン(黒塗りのハート)を押すと、Ajax処理により、

  いいねボタンが白抜きのハートへと表示が変わり、いいね数が1つ減少する。

現状(上手くいっていない箇所、操作と結果)

上記「1.」「2.」のいいね追加・取消ともに実装し、正常に動作することを確認しました。
しかし、一点不具合を見つけてしまいました。
具体的には下記の操作を行った際に起こります。
「いいね数が1以上の投稿に対し、白抜きハートのいいねボタンをクリックし、いいね追加を行う」→「その後、いいねが2以上になった投稿に対し、黒塗りのハートのいいねボタンをクリックし、いいね取消を行う」
この操作の想定結果と、実際に今起こってしまった結果は以下の通りです。

想定していた結果(実現したい結果)

いいねが取り消され、いいね数が1つ減少し、いいねボタンが白抜きに変わる。
→この後、白抜きとなっているいいねボタンを押すと、再びいいね追加処理が行える。

今起こってしまった結果

いいねが取り消され、いいね数が1つ減少するが、いいねボタンは黒塗りのハートのままとなる。
→この後、黒塗りのハートボタンを押すと、いいね取消処理が実行され、いいね数が1つ減少する。
→いいね数が0になるまで取消処理を行うことができてしまう。いいね数が0になると、ようやくいいねボタンが白抜きのハートに戻り、いいね追加処理が行えるようになる。
(問題点:いいね取消時は1つしかいいね数を減少させられないはずなのに、いいね数が0になるまでいいね取消が行えてしまう)

起こってしまった結果(不具合)現象のキャプチャ

①いいね数が1以上の投稿に対し、
イメージ説明

②白抜きハートのいいねボタンをクリックし、いいね追加を行う。
イメージ説明

③その後、いいねが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

不足情報等ございましたら、ご指摘いただいたけますと幸いです。
よろしくお願いいたします。

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

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

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

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

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

winterboum

2020/06/02 14:29

model Like、Post の関連定義を載せてください
otdsh9432

2020/06/02 14:32

コメントいただきありがとうございます。 model(post.rbとlike.rb)のソース(has_many,belongs_to)についても記載しました。 よろしくお願いいたします。
guest

回答1

0

ベストアンサー

@like = Like.find_by(like_params, user_id: current_user.id)
のところを
@like = Like.find_by(like_params.merge(user_id: current_user.id})
にしてください

投稿2020/06/02 14:42

winterboum

総合スコア23549

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

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

otdsh9432

2020/06/02 23:31

ご回答いただきありがとうございます。 記載いただいた通りに変更したところ、正常に動作することができました! 本当にありがとうございました。 ハッシュが上手く連結されておらず、find_byで意図通りに値が取れていなかったと理解できました。 mergeというメソッドが把握できていなかったので、ハッシュの連結の際は、mergeを使うようにします。 大変勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問