Ruby-on-rails ActiveRecord::RecordNotFound -- 找不到没有 ID 的用户
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1303980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ActiveRecord::RecordNotFound -- Couldn't find User without an ID
提问by MikeH
Please see UPDATES at the bottom of the question...
请参阅问题底部的更新...
For reference, this problem evolved out of some fixes I made based on a previous problem I was having here: Associating Two Models in Rails (user and profile)
作为参考,这个问题是根据我之前在这里遇到的一个问题所做的一些修复演变而来的:Associating Two Models in Rails (user and profile)
I'm building an app that has a user model and a profile model.
我正在构建一个具有用户模型和配置文件模型的应用程序。
I want to associate these models such that:
- After the user creates an account, he is automatically sent to the "create profile" page, and the profile he creates is connected to only that particular user.
- Only the user who owns the profile can edit it.
我想将这些模型关联起来:
- 用户创建帐户后,他会被自动发送到“创建个人资料”页面,并且他创建的个人资料仅与该特定用户相关联。
- 只有拥有配置文件的用户才能对其进行编辑。
I generated the user model using nifty_generators. When the user hits submit for the account creation, I redirect him to the "new profile" view to create a profile. I did this by editing the redirect path in the user controller. The user controller looks like this:
我使用 nifty_generators 生成了用户模型。当用户点击提交创建帐户时,我将他重定向到“新配置文件”视图以创建配置文件。我通过编辑用户控制器中的重定向路径来做到这一点。用户控制器如下所示:
def new
@user = User.new
end
def create
@user = User.new(params[:user])
if @user.save
session[:user_id] = @user.id
flash[:notice] = "Thank you for signing up! You are now logged in."
redirect_to new_user_profile_path(:user_id => @user)
else
render :action => 'new'
end
end
When I click 'submit' to create a new user, it now sends me to the following url, which seems right: localhost:3000/users/6/profile/new. But it throws the following exception:
当我单击“提交”以创建新用户时,它现在将我发送到以下网址,这似乎是正确的:localhost:3000/users/6/profile/new。但它抛出以下异常:
NoMethodError in ProfilesController#new You have a nil object when you didn't expect it! The error occurred while evaluating nil.build
NoMethodError in ProfilesController#new 当你没想到的时候,你有一个 nil 对象!评估 nil.build 时发生错误
The trace indicates that the problem is in the profiles controller, in the New method. The profiles controller looks like this:
跟踪表明问题出在新方法中的配置文件控制器中。配置文件控制器如下所示:
def index
@user = User.find(params[:user_id])
@profile = @user.profile(:order => "created_at DESC")
end
def show
@user = User.find(params[:user_id])
@profile = @user.profile.find(params[:id])
end
def new
@user = User.find(params[:user_id])
@profile = @user.profile.build
end
def edit
@user = User.find(params[:user_id])
@profile = @user.profile.find(params[:id])
end
def create
@user = User.find(params[:user_id])
@profile = @user.profile.build(params[:profile])
if @profile.save
flash[:notice] = 'Profile was successfully created.'
redirect_to(@profile)
else
flash[:notice] = 'Error. Something went wrong.'
render :action => "new"
end
end
Additionally, the app also throws an exception when I try to view the index page of the profiles (there are currently no profiles because I can't get past the user creation step to create one). This is the exception:
ActiveRecord::RecordNotFound in ProfilesController#index
Couldn't find User without an ID
此外,当我尝试查看个人资料的索引页面时,该应用程序也会引发异常(目前没有个人资料,因为我无法通过用户创建步骤来创建个人资料)。这是例外:
ActiveRecord::RecordNotFound in ProfilesController#index
找不到没有 ID 的用户
This is what the log is telling me:
这是日志告诉我的:
Processing ProfilesController#index [GET] Parameters: {"action"=>"index", "controller"=>"profiles"}
ActiveRecord::RecordNotFound (Couldn't find User without an ID):
app/controllers/profiles_controller.rb:5:in `index'
处理 ProfilesController#index [GET] 参数:{"action"=>"index", "controller"=>"profiles"}
ActiveRecord::RecordNotFound(无法找到没有 ID 的用户):
app/controllers/profiles_controller.rb:5:in `index'
To give you the rest of the details on the app, the models have the following associations:
Profile belongs _to :user
User has _one :profile
为了向您提供有关应用程序的其余详细信息,模型具有以下关联:
个人资料属于 _to :user
用户拥有_one :profile
I have this in the routes.rb file: map.resources :users, :has_one => :profile
我在 routes.rb 文件中有这个:map.resources :users, :has_one => :profile
In the view for the new profile page that's throwing the first exception listed above, I have this:
在抛出上面列出的第一个异常的新个人资料页面的视图中,我有这个:
<% form_for([@user, @profile]) do |f| %>
<%= f.error_messages %>
....
<% end %>
In the view for the profile index that's throwing the second exception explained above, I have this:
在抛出上面解释的第二个异常的配置文件索引的视图中,我有这个:
<% @profiles.each do |profile| %>
<div class="post">
<div class="left">
<p>Store: </p>
<p>Category: </p>
</div>
<div class="right">
<p><%=h profile.name %></p>
<p><%=h profile.category %></p>
</div>
<div class="bottom">
<p><%= link_to 'Go to profile', user_profile_path(@user, profile) %></p>
<p><%= link_to 'Edit', edit_user_profile_path(@user, profile) %></p>
<p><%= link_to 'Destroy', user_profile_path(@user, profile), :confirm => 'Are you sure?', :method => :delete %></p>
</div>
I've spent hours trying to track down the problem myself as a learning exercise, but at this point I have no idea how to fix this. Appreciate the help!
作为学习练习,我花了几个小时试图自己追踪问题,但此时我不知道如何解决这个问题。感谢帮助!
UPDATE:
更新:
jdl, per your request:
profiles/new.html.erb:
jdl,根据您的要求:
profiles/new.html.erb:
<% form_for([@user, @profile]) do |f| %>
<%= f.error_messages %>
<div class="left">
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>required
</p>
<p>
<%= f.label :category %><br />
<%= f.text_field :category %>required
</p>
<p>
<%= f.label :address1 %><br />
<%= f.text_field :address1 %>
</p>
<p>
<%= f.label :address2 %><br />
<%= f.text_field :address2 %>
</p>
<p>
<%= f.label :city %><br />
<%= f.text_field :city %>
</p>
<p>
<%= f.label :state %><br />
<%= f.text_field :state %>
</p>
<p>
<%= f.label :zip %><br />
<%= f.text_field :zip %>required
</p>
<p>
<%= f.label :phone %><br />
<%= f.text_field :phone %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
</div>
<div class="right">
<p>
<%= f.label :website %><br />
<%= f.text_field :website %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
</div>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
routes.rb:
ActionController::Routing::Routes.draw do |map|
map.signup 'signup', :controller => 'users', :action => 'new'
map.logout 'logout', :controller => 'sessions', :action => 'destroy'
map.login 'login', :controller => 'sessions', :action => 'new'
map.resources :sessions
route.rb:
ActionController::Routing::Routes.draw do |map|
map.signup 'signup', :controller => 'users', :action => 'new'
map.logout 'logout', :controller => 'sessions', :action => 'destroy'
map.login 'login' , :controller => 'sessions', :action => 'new'
map.resources :sessions
map.resources :users, :has_one => :profile
map.root :controller => "home"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
PROFILES CONTROLLER (as of 8/20/09, 8pm EST)
class ProfilesController < ApplicationController
配置文件控制器(截至 8/20/09,东部标准时间晚上 8 点)类 ProfilesController < ApplicationController
def index
@users = User.all(:order => "created_at DESC")
end
def show
@user = User.find(params[:user_id])
end
def new
@user.profile = Profile.new
end
def edit
@user = User.find(params[:user_id])
@profile = @user.profile.find(params[:id])
end
def create
@user = User.find(params[:user_id])
@profile = @user.profile.build(params[:profile])
if @profile.save
flash[:notice] = 'Profile was successfully created.'
redirect_to(@profile)
else
flash[:notice] = 'Error. Something went wrong.'
render :action => "new"
end
end
def update
@profile = Profile.find(params[:id])
if @profile.update_attributes(params[:profile])
flash[:notice] = 'Profile was successfully updated.'
redirect_to(@profile)
else
render :action => "edit"
end
end
def destroy
@profile = Profile.find(params[:id])
@profile.destroy
redirect_to(profiles_url)
end
end
Cody, the index page below is throwing the following exception:
NoMethodError in Profiles#index
Showing app/views/profiles/index.html.erb where line #14 raised:
undefined method `name' for #
Cody,下面的索引页面抛出以下异常:
NoMethodError in Profiles#index
Showing app/views/profiles/index.html.erb where line #14 raise :
undefined method `name' for #
<div id="posts">
<% @users.each do |profile| %>
<div class="post">
<div class="left">
<p>Store: </p>
<p>Category: </p>
</div>
<div class="right">
<p><%=h profile.name %></p>
<p><%=h profile.category %></p>
</div>
<div class="bottom">
<p><%= link_to 'Go to profile', user_profile_path(@user, profile) %></p>
<p><%= link_to 'Edit', edit_user_profile_path(@user, profile) %></p>
<p><%= link_to 'Destroy', user_profile_path(@user, profile), :confirm => 'Are you sure?', :method => :delete %></p>
</div>
</div>
回答by jdl
The error is telling you that in this line:
错误告诉您在这一行中:
@profile = @user.profile.build
@user.profile is nil.
@user.profile 为零。
Since you haven't created the profile yet, this makes sense. Instead, go for something like this.
由于您尚未创建配置文件,这是有道理的。相反,去做这样的事情。
@profile = Profile.new(:user_id => @user.id)
Re: The index page throwing an exception.
回复:索引页抛出异常。
You are defining @users in your controller, and then referencing @user in your path helpers. Also, iterating over @users should give you User objects, not Profile objects.
您在控制器中定义 @users,然后在路径助手中引用 @user。此外,迭代 @users 应该给你 User 对象,而不是 Profile 对象。
It looks like you're trying to use the Profile#index action to show a list of users. That's kind-of OK, in a not-quite-pure-REST way. However, I would expect to see something more like this.
您似乎正在尝试使用 Profile#index 操作来显示用户列表。以一种不太纯粹的 REST 方式,这还算可以。但是,我希望看到更多类似的东西。
<% @users.each do |user| -%>
<% unless user.profile.blank? -%>
<%= h user.profile.name %>
<%= h user.profile.category %>
<%= link_to 'Go to profile', user_profile_path(user, user.profile) %>
<% end -%>
<% end -%>
回答by penger
hmm.. I thought when User has many profiles, you can then use:
嗯..我想当用户有很多配置文件时,你可以使用:
@user.profiles.build
@user.profiles.create
when User has one profile, you have to use:
当用户有一个配置文件时,您必须使用:
@user.build_profile
@user.create_profile
Can't be sure, check API
不能确定,检查 API
回答by Rekha Benada
Do one thing
做一件事
In ProfileControllerprovide session[:user_id]not params[:user_id]
在ProfileController提供session[:user_id]不params[:user_id]
def show <br>
@user = User.find(session[:user_id])<br>
@profile = @user.profile <br>
end <br>
I hope it works!
我希望它有效!
回答by Cody Caughlan
@jdl was correct in that there is no @user.profile object in ProfilesController#new so calling @user.profile.build would throw a nil exception.
@jdl 是正确的,因为 ProfilesController#new 中没有 @user.profile 对象,所以调用 @user.profile.build 会抛出一个 nil 异常。
You can fix this by instantiating a new Profile object by
您可以通过实例化一个新的 Profile 对象来解决这个问题
@user.profile = Profile.new
Later if @user gets saved then it will trigger a @user.profile and the foreign keys will be set appropriately.
稍后如果@user 被保存,那么它将触发@user.profile 并且外键将被适当设置。
Also in your ProfilesController, the #index and #show actions are kind of weird. Conventionally, the #index action returns a "list of objects" and #show is to display just one object, a specific one given an ID. However, your #index returns a very specific object because it does a User.find with a specific ID. Furthermore, since a user only has one Profile object it doesnt make sense to also load up its Profile object with an ORDER BY. There should only be one so no order is necessary. On top of that, its debatable whether you need to explicitly load the profile object as you can just access it via @user.profile and ActiveRecord will load it on demand. So your new #index looks something like
同样在您的 ProfilesController 中,#index 和 #show 操作有点奇怪。按照惯例,#index 操作返回一个“对象列表”,而#show 只显示一个对象,一个给定 ID 的特定对象。但是,您的 #index 返回一个非常具体的对象,因为它使用特定 ID 执行 User.find。此外,由于用户只有一个 Profile 对象,因此用 ORDER BY 加载其 Profile 对象是没有意义的。应该只有一个,所以不需要顺序。最重要的是,您是否需要显式加载配置文件对象是有争议的,因为您可以通过@user.profile 访问它,而 ActiveRecord 将按需加载它。所以你的新 #index 看起来像
def index
@users = User.paginate(:all, :order = "created_at desc", :page => 1, :per_page => 10)
end
This assumes you have the WillPaginate plugin, but the gist is that you are loading a LIST of objects, not just one. In your view, if you are iterating over @users and call .profile on an element of that list then ActiveRecord will load the associated Profile on the fly.
这假设您有 WillPaginate 插件,但要点是您正在加载一个对象列表,而不仅仅是一个。在您看来,如果您迭代 @users 并在该列表的元素上调用 .profile ,则 ActiveRecord 将即时加载关联的 Profile。
Pretty same thing for #show - no need to explicitly load the profile.
#show 完全相同 - 无需显式加载配置文件。
def show
@user = User.find(params[:user_id])
end

