rrr013
@rrr013 (gororo ririr)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Railsでいいね機能 非同期通信実装中のエラーについて

解決したいこと

Ruby on Railsでいいね機能を非同期通信しようとしています。
その中で、以下のスクショのようなエラーが出てきて詰まっております。
エラーの解決方法を教えてください。

発生している問題・エラー

スクリーンショット 2023-07-15 11.33.58.png

該当するソースコード

#favoriteフォルダ _favorite.html.erb

<% if book.favorited_by?(current_user) %>
    <%= link_to book_favorites_path(book), method: :delete, remote: true, class:'text-danger' do %>
      <i class="fas fa-heart"></i><%= "#{book.favorites.count}" %>
    <% end %>
<% else %>
    <%= link_to book_favorites_path(book), method: :post, remote: true, class:'text-primary' do %>
      <i class="fas fa-heart"></i><%= "#{book.favorites.count}" %>
    <% end %>
 <% end %>
#favoriteコントローラー

class FavoritesController < ApplicationController
  before_action :authenticate_user!
  before_action :set_book
  
  def create
    @book = Book.find(params[:book_id])
    favorite = current_user.favorites.new(book_id: @book.id)
    favorite.save
  end

  def destroy
    @book = Book.find(params[:book_id])
    favorite = current_user.favorites.find_by(book_id: @book.id)
    favorite.destroy
  end
  
  
  private
  
  def set_book
    @book = Book.find(params[:book_id])
  end
  
end
#usersコントローラー

class UsersController < ApplicationController
  before_action :correct_user, only: [:edit, :update]

  def show
    @user = User.find(params[:id])
    @books = @user.books.page(params[:page])
    @book = Book.new
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
   if @user.update(user_params)
     flash[:notice] = "You have updated user successfully."
     redirect_to user_path
   else
     render :edit
   end
  end

  def index
    @users = User.all.includes(:user)
    @book = Book.new
    @user = current_user
  end

  private

  def user_params
    params.require(:user).permit(:name, :image, :introduction)
  end

  def correct_user
     @user = User.find(params[:id])
    unless @user == current_user
      redirect_to user_path(current_user.id)
    end
  end
end
#bookモデル

class Book < ApplicationRecord

  belongs_to :user
  has_many :book_comments, dependent: :destroy
  has_many :favorites, dependent: :destroy

  validates :title, presence: true
  validates :body, presence: true, length: { maximum: 200 }


  def favorited_by?(user)
    favorites.where(user_id: user.id).exists
  end

end
#users/show.html.erbでのrenderの記載
 <%= render 'favorites/favorite', book: @books %>

自分で試したこと

ここに問題・エラーに対して試したことを記載してください。

bookモデルにある

 def favorited_by?(user)
    favorites.exists(user_id: user.id)
 end

 def favorited_by?(user)
    favorite.where(user_id: user.id).exists?
 end

に変更いたしました。

favoriteコントローラーに以下の2つを記述しました。

before_action :set_book





private
  
  def set_book
    @book = Book.find(params[:book_id])
  end

初心者で、まだまだ理解が深まっていないですが、どうかよろしくお願いいたします。

0

1Answer

根本原因

bookの型がAssociationRelationであるため、favorited_by?メソッドが存在しない

対応方法

users/show.html.erbの詳細がわからないので想像で書きます。
画面構成としてはユーザー情報と本の一覧があり、本の一覧にそのユーザーが「お気に入り登録」したか?という表示をしたいのだと思います。
すでに@booksをループする処理はあると思いますので以下のように修正します。

users/show.html.erb
<% @books.each do |book| %>
  <%= render 'favorites/favorite', book: book %>
<% end %>

@booksを渡しているところをループ時に置いた変数に変えてあげるだけです。

どうしてエラーが発生しているか

おそらく<% if book.favorited_by?(current_user) %>ではBookモデルを想定しているものと思いますが、違うものがここに入っています。
順を追って説明します。

_favorite.html.erbに渡されている値

_favorite.html.erbに渡されている値は以下のように設定されています。

users/show.html.erb
<%= render 'favorites/favorite', book: @books %>

@booksの値

@booksの値はUsersController#showで設定しています。

users_controller.rb
def show
  @user = User.find(params[:id])
  @books = @user.books.page(params[:page])
  @book = Book.new
end

@booksはどのようなものか

上記より@user.books.page(params[:page])@booksに入っていることがわかりました。
@booksの中身がAssociationRelationであるため今回のエラーが発生しています。

AssociationRelationとはどのようなものか

modelのアソシエーションから取得した、modelの配列のようなものです。
配列なのでmodelのメソッドはそのままでは呼び出せません。
Book#favorited_by?を呼ぶためにはループで回して個別のインスタンスに対してメソッドを呼び出す必要があります。
よって、文頭に示した対応で本件が解決可能となります。

1Like

Comments

  1. @rrr013

    Questioner

    解決しました!
    分からないこともまだまだ多くありましたが
    とても丁寧でわかりやすく解説してくださり、なぜエラーになってしまったのかがわかりました。
    ありがとうございます!

Your answer might help someone💌