

いいね機能を実装しようとして、投稿ボタンを押したら、投稿一覧ページへ遷移するようにしたのですが、いいねボタンの部分でエラーになってしまいました。  
参考にしたのはこちらの記事です  
[Rails
いいね機能のミニアプリを作ろう](https://qiita.com/keitah/items/12b50c86bcfa9cfb4db9#likerb)

エラーで引っかかってしまっているコードは以下です

[code]

      def already_liked?(post)
        self.likes.exists?(post_id: post.id)
      end
    
[/code]

エラーメッセージは以下です。

[code]

    NoMethodError in Posts#index
    
    undefined method `id' for nil:NilClass
    
[/code]

そこで、問題のソースコードにあるところにあるコードをコメントアウトしたらエラー分は消えていいねは押せるようになったのですが、今度はその取消ができなくなってしまいました。  
どうしたらいいかわかりません。

# 問題のソースコード

user.rb(userに関するモデル)

[code]

    class User < ApplicationRecord
      # Include default devise modules. Others available are:
      # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
      devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :validatable
        
      has_one_attached :image
      has_many :comments       
      has_many :posts
      has_many :likes, dependent: :destroy
      has_many :liked_posts, through: :likes, source: :post
     
      def already_liked?(post)
        self.likes.exists?(post_id: post.id)
      end
    
    
      with_options presence: true do
        validates :nickname
        validates :mania_histry
        validates :enjoy_point
        validates :email
        validates :password, length: { minimum: 6 }
      end
    end
    
[/code]

post.rb(投稿に関するモデル)

[code]

    class Post < ApplicationRecord
        has_many_attached :images
        belongs_to :user
        has_many :likes
        has_many :liked_users, through: :likes, source: :user
    
    
        validates :content, presence: true
    
    end
    
[/code]

like.rb(いいね機能に関するモデル)

[code]

    class Like < ApplicationRecord
     belongs_to :post
     belongs_to :user
    end
    
[/code]

## ここからはコントローラーです

以下は、いいね機能に関するコントローラーです

[code]

    class LikesController < ApplicationController
      def create
        @like = current_user.likes.create(post_id: params[:post_id])
        redirect_back(fallback_location: root_path)
      end
    
      def destroy
        @like = Like.find_by(post_id: params[:post_id], user_id: current_user.id)
        @like.destroy
        redirect_back(fallback_location: root_path)
      end
    end
    
[/code]

以下は、投稿に関するコントローラーです

[code]

    class PostsController < ApplicationController
      before_action :authenticate_user!, only: [:new, :update, :create, :edit, :update, :destroy]
      before_action :find_post, only: [:edit, :update, :show, :destroy]
    
        def index
            @posts = Post.all
            @like = Like.new
          end
    
          def new
            @post = Post.new
            @like = Like.new
    
          end
    
        def show
        end
        
        
        def create
          @post = current_user
          @post = Post.create(post_params)
          if @post.save
            redirect_to root_path,notice:'投稿に成功しました'
            else
              redirect_to new_post_path,notice:'投稿に失敗しました'
            end
          end
        
          def edit
          end
    
          def update
            @post.update(post_params)
          end
    
          def destroy
            if @post.destroy
              redirect_to root_path,alert: '投稿を削除しました'
            else
              redirect_to root_path
            end
          end
    
          private
    
            def post_params
              params.require(:post).permit(:content, {images: []}).merge(user_id: current_user.id)
            end
    
            def find_post
              @post = Post.find(params[:id])
            end
    
            def force_redirect_unless_my_post
              return redirect_to root_path,alert:'権限がありません'if @post.user != current_user
            end
    end
    
[/code]

以下は、ビューです

[code]

    <div class="content-wrapper">
        <div class="content-block">
            <% @posts.each do |post| %>
            <div class="content">
             <div class="user-about">
                 <div class="image">
                 <% if post.user.image.attached? %>
                 <%= image_tag post.user.image %>
                    <% else %>
                <%= image_tag no.user.png %>
                    <% end %>
                 </div>
    
             <div class="profile">
                <div class="name-history">
                    <div class="name">
    
                    <%= post.user.nickname %>
    
    
                    </div>
                    <div class="mania-histry">
                        <%= "学習歴:#{post.user.mania_histry}年" %>
                    </div>
                 </div>
                 
                 <div class="enjoy-point">
                 <%= "楽しいポイント#{post.user.enjoy_point}"%>
                 </div>
             </div>
           </div>
           
           <div class="text">
            <p><%= post.content %></p>
        </div>
            <% if post.images.attached? %>
            <% post.images.each do |image| %>
                <div class = 'images'>
                    <%= image_tag image %>
                </div>
            <% end %>
            <% end %>
             <div class="action-menu">
                <% if user_signed_in? %>
                 <div class="like">
                 <h3>いいね件数: <%= post.likes.count %></h3>
                 <div class = 'like-button'>
                    <% if current_user.already_liked?(post.id) %>
                    <%= button_to 'いいねを取り消す', post_like_path(post), method: :delete %>
                 <% else %>
                   <%= button_to 'いいね', post_likes_path(post) %>
                 <% end %>
    
                </div>
                </div>
                <% end %>
                 <div class="comment">
                     
            </div>
             </div>
    
            </div>
            <% end %>
    
    
        </div>
        <div class="sidebar">
         <div class="box">
    
         </div>
         <div class="box">
             
        </div>
        </div>
    </div>
    
[/code]

# 試してみたこと

ご指摘させていただいたとおりにviewの48行目の  
`<% if current_user.already_liked?(post.id) %>`の部分を  
`<% if current_user.already_liked?(@post) %>`に変更してみましたが変化なしでした。  
もう一つは、いいね機能に関するコントローラーのストロングパラメーターを

[code]

    @like = current_user.likes.create(post_id: params[:post_id])
    
[/code]

から

[code]

    @like = current_user.likes.create(post_id: post_id)
    
[/code]

に変更してみたのですが何も変わりませんでした。  
likeコントローラーにnewメソッドがないからかなと思い、

[code]

      def new
        @like = Like.new
      end
    
[/code]

を追加したあとにroutes.rbにもnewメソッドを追加、投稿のコントローラーの方にあった記述は削除しました、そうしたらエラー分が以下に変わりました。

[code]

    ActionController::UrlGenerationError in Posts#index
    
    No route matches {:action=>"destroy", :controller=>"likes", :post_id=>#<Post id: 1, content: "asdf", created_at: "2021-03-26 23:40:56", updated_at: "2021-03-26 23:40:56", user_id: 1>}, missing required keys: [:id]
    
[/code]

post.idは取得できているようですが、全部の情報を受け取ってしまっているみたいでできないのかなって考えたのですが、その次のアクションプランがわかりません。


CC BY-SA 4.0
2021-03-26T08:53:23.783
74900
2022-07-06T10:00:05.040
2021-03-27T02:35:23.203
40506
40506
question
ruby-on-rails ruby
いいね機能を作りたいのに外部キーが参照されなくてundefined method `id' for nil:NilClassになってしまう


`already_liked?` メソッドは Post クラスのインスタンスが引数に渡されることを期待しています。

[code]

    def already_liked?(post)
      self.likes.exists?(post_id: post.id)
    end
    
[/code]

一方で元々のビューにおいては、`already_liked?` メソッドに対して整数を渡していました。

[code]

    <% if current_user.already_liked?(post.id) %>
    
[/code]

したがってこの部分で既に何かおかしいです。どちらかに揃える必要があります。たとえば参考になさっている記事では Post
クラスのインスタンスが渡されるようにしていますね。

「試してみたこと」として追記されたビューにおいては、`post` ではなく `@post` を渡していました。

[code]

    <% if current_user.already_liked?(@post) %>
    
[/code]

PostsController#index のおいては `@posts` は存在しますが `@post` は存在しません。`post`
を渡すようにすべきです。


CC BY-SA 4.0
2021-03-26T13:05:20.190
74916
2021-03-28T06:12:01.703
2021-03-28T06:12:01.703
19110
19110
74900
answer


こちらの記事を参考にしました。  
[【Rails】いいね機能完全版！同期いいね、いいね数の表示、非同期いいね、アイコン表示、それぞれの実装方法についてまとめて解説](https://techtechmedia.com/favorite-
function-rails/)

そして、ビューファイルの記述(いいね機能の部分)を

[code]

    <% if user_signed_in? %>
      <div class="like">
        <h3>いいね件数: <%= post.likes.count %></h3>
        <div class='like-button'>
          <% if current_user.liked_by?(post.id) %>
           　<td><%= link_to 'いいねを外す', destroy_like_path(post), class: "like-link", method: :DELETE %></td>
             <i class="fa fa-heart unlike-btn"></i>
          <% else %>
             <td><%= link_to 'いいね', create_like_path(post), class: "like-link", method: :create %></td>
             <i class="fa fa-heart like-btn"></i>
          <% end %>
    
[/code]

ユーザーモデルの記述を

[code]

    def liked_by?(post_id)
      likes.where(post_id: post_id).exists?
    end
    
[/code]

に変更したら解決できました。


CC BY-SA 4.0
2021-03-28T01:03:16.760
74937
2021-03-28T03:30:05.263
2021-03-28T03:30:05.263
7500
40506
74900
answer