Leem.fin
Leem.fin

Reputation: 42602

Rails : Why nil object in my view

I have created a very simple Rails 3.1 app with basic stuffs like following:

My PostsController.rb has new, index, create methods:

def index
    @posts = Post.all

    render :index
end
def new
   @post = Post.new
   render :new
end

def create
    @post = Post.new(params[:post])

    if @post.save
      render :index

    else
      render :new

    end

  end

The new.html.erb form:

<%= form_for @post do |f| %>
  <%= f.error_messages%>
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :address %><br />
    <%= f.text_field :address, :size=>60 %>
  </p>

  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

the index view (index.html.erb):

<table>
<% @posts.each do |post| %>
  <tr>
    ...
  </tr>
<% end %>
</table>

my routes.rb has defined:

resources :posts
root :to => 'post#new'

With all above, when the new form is submited, the create method in PostController will be invoked, then inside the create method, if the new post is saved successfully, it will render :index,that's to render the index.html.erb view, things are fine at this point. but I got a error now in index.html.erb view:

It complains that the @posts in <% @posts.each do |post| %> is nil, why???

-------------I also tried-------------------------

I tried to use redirect_to posts_path in create method, then I got undefined method `posts_path_url' error

I also tried to use redirect_to :index in create method, then I got undefined method `index_url' error

Upvotes: 2

Views: 983

Answers (2)

Tomas
Tomas

Reputation: 714

This happens because a call to render does not invoke the index method on the controller, it only resolves the path to the view and renders it.

If you want @posts to be present you must set it yourself in your create action.

This works well with the default new and create methods (scaffold generated) because in both actions you set up the same instance variable @post. Only in the create action if the validation fails you can instantly reuse the @post instance variable that has different errors stored on it and render the new view template to show the post form with errors.

If you want to redirect to the posts action you should use:

redirect_to posts_path

Upvotes: 0

maro
maro

Reputation: 1506

The error happens because @posts variable is not set in your Post#create method as it is in Post#index. You have to remember that rendering a view doesn't call appropriate controller method.

You want to use redirect_to instead of render:

def create
    @post = Post.new(params[:post])

    if @post.save
        redirect_to :posts
    else
        render :new
    end
end

Upvotes: 2

Related Questions