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

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

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

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

Ruby on Rails

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

非同期処理

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

Ajax

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

Q&A

解決済

1回答

1309閲覧

非同期のいいね機能でNameError in Posts#indexを解決したい【Rails】

tokenoko

総合スコア5

Ruby

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

Ruby on Rails

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

非同期処理

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

Ajax

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

0グッド

0クリップ

投稿2020/11/10 12:31

前提・実現したいこと

Ruby:2.6.6
Rails:5.2.4

投稿に対して、「いいね」する機能を非同期処理で付けたいと考えています。

発生している問題・エラーメッセージ

モデル・コントローラー・ビュー・create.js.erb・destroy.js.erbの作成が終わったので確認しようとしたところ、投稿の一覧ページで
NameError in Posts#index
undefined local variable or method ’post'
となり、投稿一覧ページが表示されません。
初歩的な部分で、タイプミスや定義の抜けがあると思っていますが、原因が見つけられません。

ご指摘・アドバイスいただけますと嬉しいです。

エラーメッセージ

NameError in Posts#index Showing /app/app/views/posts/index.html.erb where line #14 raised: undefined local variable or method `post' for #<Post:0x000055a8aab95908> Extracted source (around line #23): def liked_by(user) Like.find_by(user_id: user.id, post_id: id) end private

該当のソースコード

routes.rb

ruby

1Rails.application.routes.draw do 2 root 'posts#index' 3 4 resources :posts do 5 resources :comments, only: [:create, :destroy] 6 resources :likes, only: [:create, :destroy] 7 end 8 9 devise_for :users, 10 controllers: {registrations:'registrations'} 11 12 get '/users/:id', to:'users#show', as: 'user' 13 14end 15

app/models/like.rb

ruby

1 2class Like < ApplicationRecord 3 belongs_to :user 4 belongs_to :post 5 6 validates :user_id, uniqueness: { scope: :post_id } 7 8end 9

app/models/post.rb

ruby

1class Post < ApplicationRecord 2 belongs_to :user 3 has_many :comments, dependent: :destroy 4 has_many :likes, dependent: :destroy 56 ・ 7 ・ 8 validates :user_id, presence:true 9 validates :content, presence:true, length: { maximum: 140 } 10 validate :image_size 11 12 def liked_by(user) 13 Like.find_by(user_id: user.id, post_id: id) 14 end 15 16 private 17 18 if image.size > 5.megabytes 19 errors.add(:image, "5MBを超える画像は投稿できません") 20 end 21 end 22end 23

app/controllers/likes_controller.rb

class LikesController < ApplicationController before_action :authenticate_user! def create @like = current_user.likes.build(like_params) @post = @like.post if @like.save respond_to :js end end def destroy @like = Like.find_by(id: params[:id]) @post = @like.post if @like.destroy respond_to :js end end private def like_params params.permit(:post_id) end end

app/views/posts/index.html.erb

ruby

1<div class="container"> 2 <h2 class="mb-4 text-center">タイムライン</h2> 3 <div class="main posts-index"> 4 <div class="container"> 5 <div class="mb-2 mx-auto col-md-6"> 6 <% @posts.each do |post| %> 7 <div class="posts-index-item border"> 8 <%= link_to(post.user.username, "/users/#{post.user_id}") %><br> 9 <%= link_to(post.content, "/posts/#{post.id}") %><br> 10 <%= image_tag post.image.url if post.image? %> 11 12 13 <div id="like-icon-post-<%= post.id.to_s %>"> 14 <% if post.liked_by(current_user).present? %> 15 <%= link_to "いいねを取り消す", post_like_path(post.id, post.liked_by(current_user)), method: :DELETE, remote: true %> 16 <% else %> 17 <%= link_to "いいね", post_likes_path(post), method: :POST, remote: true %> 18 <% end %> 19 </div> 20 21 22 <div id="comment-post-<%= post.id.to_s %>"> 23 <%= render 'comment_list', { post: post } %> 24 </div> 25 26 <div id="comment-form-post-<%= post.id.to_s %>"> 27 <%= form_with model: [post, Comment.new] do |f| %> 28 <%= f.text_field :comment, class: "form-control comment-input border-0", placeholder: "コメント", autocomplete: :off %> 29 <%= f.hidden_field :user_id, value: current_user.id %> 30 <%= f.hidden_field :post_id, value: post.id %> 31 <% end %> 32 </div> 33 </div> 34 </div> 35 <% end %> 36 </div> 37 </div> 38 </div> 39

試したこと

1.メソッドの変更

def liked_by(user) Like.find_by(user_id: user.id, post_id: id) end

このメソッドが間違っていると考え、こちらのコードを削除。
下のコードをmodels/user.rbに入れました。

def already_liked?(post) self.likes.exists?(post_id: post.id) end

viewも一部変更しました。

<div id="like-icon-post-<%= post.id.to_s %>"> <% if current_user.already_liked?(post) %> <%= link_to "いいねを取り消す", post_like_path(post.id, post.liked_by(current_user)), method: :DELETE, remote: true %> <% else %> <%= link_to "いいね", post_likes_path(post), method: :POST, remote: true %> <% end %> </div>

しかしエラーは解決せず

NoMethodError in Posts#index Showing /app/app/views/posts/index.html.erb where line #14 raised: undefined method `already_liked?' for #<User:0x000055a8a7f8bfb0> Extracted source (around line #14): <div id="like-icon-post-<%= post.id.to_s %>"> <% if current_user.already_liked?(post) %> <%= link_to "いいねを取り消す", post_like_path(post.id, post.liked_by(current_user)), method: :DELETE, remote: true %> <% else %> <%= link_to "いいね", post_likes_path(post), method: :POST, remote: true %>

となりました

2.メソッドのミスか確認
Like.find_by(user_id: user.id, post_id: id)に正しくpostが代入できていないのかと考え、rails consoleで確認したところ

irb(main):006:0> Like.find_by(user_id: 1,post_id: 1) Like Load (13.0ms) SELECT "likes".* FROM "likes" WHERE "likes"."user_id" = ? AND "likes"."post_id" = ? LIMIT ? [["user_id", 1], ["post_id", 1], ["LIMIT", 1]] "likes"."post_id" = ? LIMIT ? [["user => #<Like id: 1, post_id: 1, user_id: 1, created_at: "2020-11-08 07:52:58", updated_ at: "2020-11-08 07:52:58">

3.コントローラーの挙動の確認
コントローラーでpost_idが指定されていないのかと考え、rails consoleで確認しました。

destroyの確認

irb(main):002:0> @like = Like.find_by(id: 4) => #<Like id: 4, post_id: 3, user_id: 1, created_at: "2020-11-10 01:06:30", updated_at: "2020-11-10 01:06:30"> irb(main):003:0> @post = @like.post Post Load (0.5ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? ORDER BY "posts"."created_at" DESC LIMIT ? [["i irb(main):004:0> @like.destroy (0.1ms) begin transaction created_at: "2020-11-10 00:58:52", upd Like Destroy (1.4ms) DELETE FROM "likes" WHERE "likes"."id" = ? [["id", 4]] (180.3ms) commit transaction => #<Like id: 4, post_id: 3, user_id: 1, created_at: "2020-11-10 01:06:30", updated_ at: "2020-11-10 01:06:30"> irb(main):005:0> Like.find_by(id: 4) Like Load (0.4ms) SELECT "likes".* FROM "likes" WHERE "likes"."id" = ? LIMIT ? at: "2020-11-10 01:06:30"> [["id", 4], ["LIMIT", 1]] => nil

cerateもできていました。

ご指摘・アドバイス等ありましたら、よろしくお願いいたします。

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

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

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

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

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

asm

2020/11/10 23:55

railsの再起動で直りそうな印象ですが、如何でしょうか?
tokenoko

2020/11/11 13:48

ご連絡遅くなり申し訳ございません。 Dockerで環境構築をしていますが、 一度、docker-composeをSTOPしてSTARTしたらページが表示されるようになりました!! ご指摘いただきありがとうございます!! 大変初歩的な質問なのですが、どうしてこうなってしまうのでしょうか? 該当エラーの「postがない」、というのは「サーバーが更新されていないのでpostの投稿が反映されていない」ということを意味しているということでしょうか。 よろしければ教えていただけますと嬉しいです。
guest

回答1

0

ベストアンサー

大変初歩的な質問なのですが、どうしてこうなってしまうのでしょうか?

該当エラーの「postがない」、というのは「サーバーが更新されていないのでpostの投稿が反映されていない」ということを意味しているということでしょうか。

よろしければ教えていただけますと嬉しいです。

まず、この現象の奇妙なところは

  • undefined local variable or method ’post'となっているのに表示されているソースにはpostが見つからない
  • Userに追加されている筈なのにundefined method already_liked?' for #User:0x000055a8a7f8bfb0`が表示される

と、どうもRailsが実行しているソースとファイル上のソースに何故か不整合が生じているようです。

なので、Railsを再起動してソースを読み込み直したところ正常化した感じです。


Railsは開発環境では定数(Postなどのクラス名)を取得する際に
ファイルの更新を確認し、更新されているようならばそのファイルを再読み込みする仕組みがあります。

今回はなぜかその仕組みが破壊されていたようです。

原因として考えられるのは

  • require Rails.root.join "app/model/post"等によって上記の再読み込みの仕組みを破壊していた
  • DockerやOSのバグかなにかで更新が伝わらなかった可能性

あたりが思いつきますが断定はできません。

投稿2020/11/11 23:56

asm

総合スコア15149

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

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

tokenoko

2020/11/12 11:48

とても丁寧なご回答ありがとうございました! 自分のコードのミスが原因とばかり思っていましたので、そこだったのか...という気持ちです。 原因につきましても推測ということですが、大変勉強になりました。 今後もこういった可能性を考えつつ作業します。 無事、いいね機能を実装できました。 ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問