NoMethodError in Users#showのエラー解決
Railsチュートリアル第2章の演習問題で、以下のエラーが出た。
直面したエラー
NoMethodError in Users#show
Showing /workspaces/toy_app/app/views/users/_user.html.erb where line #14 raised:
undefined method `micropost' for #<User id: 1, name: "takashi", email: "takashi@abc.com", created_at: "2024-01-03 03:51:21.095067000 +0000", updated_at: "2024-01-03 03:54:10.553318000 +0000">
エラーの意味
UsersControllerのshowアクションで定義されていない「micropost」というメソッドが使われている、と指摘された。
やりたいこと
ユーザーのshowページを編集し、ユーザーの最初のマイクロポストを表示したい。
何をしたらエラーが出たか
ユーザーのshowページのビューで、user.micropost
でユーザーのマイクロポストを取得しようとしたらエラーが出た。
<div id="<%= dom_id user %>">
<p>
<strong>Name:</strong>
<%= user.name %>
</p>
<p>
<strong>Email:</strong>
<%= user.email %>
</p>
#ここでエラーが出た
<p>
<strong>micropost:</strong>
<%= user.micropost %>
</p>
</div>
まだ理解しきれていないが、本来ユーザーのshowページのビューはuser.show.html.erb
であるが、部分テンプレートで_user.html.rb
を呼び出している。
<p style="color: green"><%= notice %></p>
#部分テンプレート
<%= render @user %>
<div>
<%= link_to "Edit this user", edit_user_path(@user) %> |
<%= link_to "Back to users", users_path %>
<%= button_to "Destroy this user", @user, method: :delete %>
</div>
エラー時のUsersControllerのshowアクションは以下のとおり。
class UsersController < ApplicationController
before_action :set_user, only: %i[ show edit update destroy ]
def show
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
end
# Only allow a list of trusted parameters through.
def user_params
params.require(:user).permit(:name, :email)
end
end
やったこと
- ユーザーモデルとマイクロポストモデルの関連付けがされているか確認
-
user.micropost
からuser.microposts
に変更 -
user.micropost.first
に変更 -
user.micropost.first.content
に変更
ユーザーモデルとマイクロポストモデルの関連付け
マイクロポストとユーザーの関連付けをしていなかったので行った。
class User < ApplicationRecord
has_many :microposts
end
class Micropost < ApplicationRecord
belongs_to :user
end
ただこれを行っただけではエラーは解決しなかった。
user.micropost
からuser.microposts
に変更
ビューのユーザーのマイクロポストを取得するところをuser.micropost
からuser.microposts
に変更した。
<p>
<strong>micropost:</strong>
#以下をuser.micropostsに変更した
<%= user.micropost %>
</p>
Railsチュートリアルの解説に以下の説明があり、
first_user.micropostsを実行することで、最初のユーザーが投稿したすべてのマイクロポストを取得します。
ユーザーモデル(テーブル)とマイクロポストモデル(テーブル)は1対多の関係だから、micropost
ではなくmicroposts
とすべきと考えた。
変更した結果、エラーは出なくなったが、以下の表示になった。
micropost: #<Micropost::ActiveRecord_Associations_CollectionProxy:0x00007efdd1816f48>
user.micropost.first
に変更
micropost: #<Micropost::ActiveRecord_Associations_CollectionProxy:0x00007efdd1816f48>
この表示の意味はまだ理解しきれていないが、おそらくどのマイクロポストなのか特定していないのが原因ではないかと考え、ユーザーの最初のマイクロポストを表示するため、.first
を付け足した。
変更した結果、エラーは出なくなったが、以下の表示になった。
micropost: #<Micropost:0x00007efdd1844380>
user.micropost.first.content
に変更
micropost: #<Micropost:0x00007efdd1844380>
この表示の意味はまだ理解しきれていないが、おそらくまだ指定が足りないのが原因ではないかと推測した。
そもそもマイクロポストの内容がどうなっているかを確認した。
マイクロポストのビューを見てみると、Content
とUser
があるとわかった。
<div id="<%= dom_id micropost %>">
<p>
<strong>Content:</strong>
<%= micropost.content %>
</p>
<p>
<strong>User:</strong>
<%= micropost.user_id %>
</p>
</div>
今回はユーザーのshowページに、ユーザーの最初のマイクロポスト(の内容)を表示したいので、.content
を付け足した。
その結果、ユーザーのshowページに、ユーザーの最初のマイクロポスト(の内容)を表示することができた。
micropost: Railsチュートリアルで学習中です
解決時の内容は以下のとおり。
<p>
<strong>micropost:</strong>
<%= user.microposts.first.content %>
</p>
エラーが生じた原因
今回エラーが生じた原因は、UsersControllerのshowアクションで定義されていない「micropost」というメソッドが使われている、だった。
最初は、UsersControllerのshowアクションにメソッドを追記すべきなのかと考えたが、メソッドにはRailsのコントローラーで定義する以外にも存在すると知った。
firstメソッド:モデルのコレクションから先頭のレコードを取得する。
モデルのコレクション.first(取得する件数=nil)
エラーは出なくなったが、.microposts
と.content
はどういう類のメソッドで、user.microposts.first.content
を完全に説明できるようになっていないので、メソッドの理解を深めていきたい。
参考記事
Discussion