views:

35

answers:

3

I'm working through the railtutorial.org online book for rails 3. I've made it through most of chapter 11, where we add the ability to submit a micropost. After adding the appropriate code, I'm unable to render the page. The following is the error returned:
>

NoMethodError in Pages#home

Showing c:/rails_projects/sample_app/app/views/shared/_error_messages.html.erb where line >#1 raised:

You have a nil object when you didn't expect it! You might have expected an instance of ActiveRecord::Base. The error occurred while evaluating nil.errors Extracted source (around line #1):

1:<% if @user.errors.any? %>
2:<div id="error_explanation">
3:<h2><%= pluralize(@user.errors.count, "error") %>
4:prohibited this <%= object.class.to_s.underscore.humanize.downcase %>
Trace of template inclusion: app/views/shared/_micropost_form.html.erb, >app/views/pages/home.html.erb

The page will render correctly if I remove the following line from app\views\shared_micropost_form.html.erb <%= render 'shared/error_messages', :object => f.object %>

Any help is appreciated.

A: 

This is telling you the @user object is nil. You should make sure that in your controller pages#home, that you actually set a value for @user. If you're redirecting to the home page after rescuing an error on a form post, then you won't still have the instances variable @user after redirecting. It's most common practice if you want to include the original posted values in a form post error message to render a view so you still have the posted params at hand:

# Some controller
def create
  begin
    @user = User.create(params[:user])
  rescue ActiveRecord::RecordInvalid => e
    @errors => e.record.full_error_messages
    render :action => "new"
  end
end

I'm not sure what the tutorial is having you do, but if you post the code that's in pages_controller#home then we could tell you more.

Jeremy
+4  A: 

it's because you're passing a variable object into your partial, but in the partial you're trying to use a variable called @user. Change each instance of @user in that partial to object and it will work fine.

1:<% if object.errors.any? %>
2:<div id="error_explanation">
3:<h2><%= pluralize(object.errors.count, "error") %>
4:prohibited this <%= object.class.to_s.underscore.humanize.downcase %>

UPDATE: Just to clarify, the answers above are assuming there's a fault with setting the @user variable, but it's fine. When you say :object => f.object in your render call, you're telling render to take the object that this form is based on, and send it to the partial - with the variable name object.

The whole point of refactoring the error code into a shared partial is that it will be used by multiple forms, for different models. Inside the partial you can't say @user because you will be using this same partial for all your other models. That's why the code in the partial is changed to use a more generic variable name, object.

Jaime Bellmyer
Thanks for the explanation. I must have missed the section in chapter 10 where that partial was refactored.
alphanumericone
A: 

It seems that there's no @user variable in the controller action you're accessing

I'd try

<% if @user && @user.errors.any? %>

if there is a @user, then it will check @user.errors.any

also, if you're using devise, you could try

<% user_signed_in? && @user.errors.any? %>
vrsmn