Reputation: 42602
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
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
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