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

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

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

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

Ruby on Rails

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

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Ajax

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

Q&A

解決済

1回答

973閲覧

Ajax非同期処理のいいねの投稿のみ挙動しない

denisov

総合スコア6

Ruby

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

Ruby on Rails

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

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Ajax

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

0グッド

0クリップ

投稿2021/05/29 11:54

□解決したいこと

いいね機能をAjaxにて実装したいと考えております。

https://gyazo.com/4981862a465699475bcfec773839c50d

以上の動画のようにいいねの解除はできるのですが、いいねを新しく投稿すると

ActionView::Template::Error (No route matches {:action=>"destroy", :controller=>"likes", :tip_id=>#<Tip id: 25, title: "テスト", category_id: 4, description: "Lorem ipsum dolor sit amet, consectetur adipiscing...", user_id: 1, created_at: "2021-05-20 13:57:31", updated_at: "2021-05-27 22:59:36", image: nil>}, missing required keys: [:id]): 1: <% if user_signed_in? %> 2: <% if current_user.already_liked?(@tip)%> 3: <%= link_to tip_like_path(@tip),method: :delete, remote: true do %> 4: <i class="fas fa-heart unlike-btn"></i> 5: <% end %> 6: <% else %> app/views/likes/_like_partial.html.erb:3 app/views/likes/create.js.erb:1

以上のエラーが発生します。

rails での実装に挙動は問題ないのですが、非同期処理のいいねを押す挙動だけうまくいきません。

□仮説及び調べたこと

エラー構文の中で:action=>"destroy"が行われています。今回は新たにいいねを押すため、destroyではなくpostが起動するはずです。

つまり、2行目

<% if current_user.already_liked?(@tip)%>

が正常に起動しておらず、条件分岐ができていないと考えました。

likes_controllerでbinding.pryで値を取得して確認しました。

def create @like = current_user.likes.new(tip_id: params[:tip_id]) @tip = Tip.find_by(id: params[:tip_id]) binding.pry @like.save end [1] pry(#<LikesController>)> current_user.already_liked?(@tip) Like Exists? (0.4ms) SELECT 1 AS one FROM `likes` WHERE `likes`.`user_id` = 2 AND `likes`.`tip_id` = 25 LIMIT 1 ↳ app/models/user.rb:17:in `already_liked?' => false

current_user.already_liked?(@tip)を打ち込んで確認しましたが、

値はfalseとなりました。つまり、現在のユーザーはいいねをしていない状態ということです。

これからいいねをしようとしている状態ですので、状態としては問題ないはずです。

しかし、actionはdestroyとなっており、if current_user.already_liked?(@tip)がtrueである場合の挙動をしております。

なぜこのような挙動となるかがわかりません。

もし、何か原因がお分かりの方がいらっしゃいましたらご教示ただきたくお願い申し上げます。

##□環境

rails (6.0.3.7)

ruby 2.6.5

 ##□問題のコード

html

1tips/show.html 2 3<div class = "wrapper"> 4 <%= render "shared/header" %> 5 <div class="main-tips-show"> 6 <div class="like-show" id='likes_buttons_<%= @tip.id %>'> 7 <%= render partial:'likes/like_partial' %> 8 </div> 9 <以下省略>

html

1_like_partial/html.erb 2 3<% if user_signed_in? %> 4 <% if current_user.already_liked?(@tip)%> 5 <%= link_to tip_like_path(@tip),method: :delete, remote: true do %> 6 <i class="fas fa-heart unlike-btn"></i> 7 <% end %> 8 <% else %> 9 <%= link_to tip_likes_path(@tip),method: :post, remote: true do %> 10 <i class="far fa-heart like-btn" ></i> 11 <% end %> 12 <% end %> 13<% else %> 14 <i class="far fa-heart like-btn" ></i> 15<% end %> 16<p><%=@tip.likes.count %> </p>

ruby

1create.js.erb 及び destroy.js.erb 2 3$('#likes_buttons_<%= @tip.id %>').html("<%= j(render partial: 'likes/like_partial') %>");

ruby

1likes_controller.rb 2 3class LikesController < ApplicationController 4 def create 5 @like = current_user.likes.new(tip_id: params[:tip_id]) 6 @tip = Tip.find_by(id: params[:tip_id]) 7 binding.pry 8 @like.save 9 end 10 11 def destroy 12 @like = Like.find_by(tip_id: params[:tip_id], user_id: current_user.id) 13 @like.destroy 14 @tip = Tip.find_by(id: params[:tip_id]) 15 end 16end

ruby

1 2user.rb 3 4class User < ApplicationRecord 5 devise :database_authenticatable, :registerable, 6 :recoverable, :rememberable, :validatable 7 8 validates :nickname, presence: true, length: { maximum: 6 } 9 validates :password, presence: true, format: { with: /[a-z\d]{6,}/i, message: 'は半角英数6文字以上としてください' } 10 with_options presence: true, format: { with: /\A[ぁ-んァ-ヶ一-龥々]+\z/, message: 'には全角文字を使用してください' } do 11 validates :last_name 12 validates :first_name 13 end 14 15 has_many :tips 16 has_many :comments 17 has_many :likes 18 has_many :liked_tips, through: :likes, source: :tip 19 def already_liked?(tip)       #←すでにいいねしているかの記述 20 self.likes.exists?(tip_id: tip.id)  21 end 22end

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

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

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

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

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

guest

回答1

0

ベストアンサー

postが起動しているんです。
結果 likeが作られて、already_liked? の状態となります。
viewを書き換えるときにエラーとなっています。

ということで再描画するときの @tip があやしいのですが、
binding.pry のタイミングで @tipはどうなってますか?

投稿2021/05/29 12:24

winterboum

総合スコア23329

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

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

denisov

2021/05/29 12:40 編集

ご回答ありがとうございます。 postが起動しているんです。 結果 likeが作られて、already_liked? の状態となります。 viewを書き換えるときにエラーとなっています。 → like(いいね)を実行した後にalready_liked?のフィルタリングがかかるために、already_liked?はtrueとなってしまう。そのためmethod:destroyとなる ということでしょうか。初心者のため、認識違いがりましたら申し訳ございません。 ということで再描画するときの @tip があやしいのですが、 binding.pry のタイミングで @tipはどうなってますか? → 質問の位置の binding.pryの位置にて行いました。 ``` [1] pry(#<LikesController>)> @tip => #<Tip:0x00007fa077de9fd0 id: 25, title: "テスト", category_id: 4, description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", user_id: 1, created_at: Thu, 20 May 2021 13:57:31 UTC +00:00, updated_at: Thu, 27 May 2021 22:59:36 UTC +00:00, image: nil> ```
winterboum

2021/05/30 00:00

tip_like_path なので、tip と like の idが必要です。like のが渡っていないですね。
denisov

2021/05/30 07:03 編集

ご回答ありがとうございます。 tip_like_path なので、tip と like の idが必要です。like のが渡っていないですね。 →@tipにlike_idを付与することで <%= link_to tip_like_path(@tip),method: :delete, remote: true do %> が実行できるのではないかということでしょうか。 今回はこれからいいねをする挙動がうまくいっていない状態ですので、likeの idはnilではないでしょうか。 なお、同じbynding.pryの位置で@likeを入れてみたところnilとなりました。 ``` [1] pry(#<LikesController>)> @like => #<Like:0x00007f875fed1398 id: nil, tip_id: 25, user_id: 1, created_at: nil, updated_at: nil> ``` 今回はpostメソッドを実行したいのでtip_likes_pathを実行させるため、<%= link_to tip_like_path(@tip),method: :delete, remote: true do %>を実行させないように、<% if current_user.already_liked?(@tip)%>で正しくフィルタリングするものと思っておりました。 私の理解が甘く意図を理解できないようでしたら申し訳ございません。
winterboum

2021/05/30 07:44 編集

いえ、そこ(save)はうまくいって、結果表示で失敗してます、 ですので、@likeはidもっているはず
denisov

2021/05/30 10:24 編集

ご回答ありがとうございます。 アドバイスを参考にしたところ同様の質問者様がいらっしゃったので参考にしました。 https://teratail.com/questions/289782 <%= link_to tip_like_path(@tip,@like),method: :delete, remote: true do %> とし、@likeと@tip の2つのidを取ろうと思いましたが、うまく行きませんでした。 likeのidがnilでした。 ``` ActionView::Template::Error (No route matches {:action=>"destroy", :controller=>"likes", :id=>nil, :tip_id=>"25"}, missing required keys: [:id]): 1: <% if user_signed_in? %> 2: <% if current_user.already_liked?(@tip)%> 3: <%= link_to tip_like_path(@tip, @like),method: :delete, remote: true do %> 4: <i class="fas fa-heart unlike-btn"></i> 5: <% end %> 6: <% else %> app/views/likes/_like_partial.html.erb:3 app/views/tips/show.html.erb:5 ``` こちらのエラーはrails上でのエラー(ページで表示)でした。
winterboum

2021/05/30 11:09 編集

binding.pry のところで @like.save して、 @like と @like.errors.messages を見てください
denisov

2021/05/30 11:29

ご回答ありがとうございます。 以下内容となります。 2: def create 3: @like = current_user.likes.new(tip_id: params[:tip_id]) 4: @tip = Tip.find_by(id: params[:tip_id]) => 5: binding.pry 6: @like.save 7: end [1] pry(#<LikesController>)> @like.save (0.3ms) BEGIN ↳ (pry):1:in `create' Tip Load (1.6ms) SELECT `tips`.* FROM `tips` WHERE `tips`.`id` = 25 LIMIT 1 ↳ (pry):1:in `create' Like Exists? (0.6ms) SELECT 1 AS one FROM `likes` WHERE `likes`.`tip_id` = 25 AND `likes`.`user_id` = 1 LIMIT 1 ↳ (pry):1:in `create' Like Create (9.9ms) INSERT INTO `likes` (`tip_id`, `user_id`, `created_at`, `updated_at`) VALUES (25, 1, '2021-05-30 11:22:37.624287', '2021-05-30 11:22:37.624287') ↳ (pry):1:in `create' (1.3ms) COMMIT ↳ (pry):1:in `create' => true [2] pry(#<LikesController>)> @like => #<Like:0x00007faee2b4cdf8 id: 151, tip_id: 25, user_id: 1, created_at: Sun, 30 May 2021 11:22:37 UTC +00:00, updated_at: Sun, 30 May 2021 11:22:37 UTC +00:00> [3] pry(#<LikesController>)> @like.errors.messages => {} 何度も申し訳ございません。
denisov

2021/05/31 13:05

_like_partial.html.erb <%= link_to tip_like_path(@tip),method: :delete, remote: true do %> を <%= link_to tip_like_path(id: @tip.likes[0].id, tip_id: @tip.id),method: :delete, remote: true do %> としたらできました。 ご指摘の通り、idが指定されていなかったことが原因でした。 @tipからlikeのidを指定することで解決できました。 ありがとうございましました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問