前提・実現したいこと
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 5 ・ 6 ・ 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もできていました。
ご指摘・アドバイス等ありましたら、よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー