Reputation: 13
I'm trying to write my first custom controller action and am running into a NoMethodError.
The scenario: PostsController, with the standard 7 actions scaffolding generates.
I want the index page to show a single post instead of displaying a list of them. Each post has a "visible" checkbox. I created a named_scope
called visible
in the Post model with:
named_scope :visible, :conditions => ["visible =?", true]
and applied it along with .last to the index action in my controller:
def index
@post = Post.visible.last
(format stuff)
end
Edited my index view to remove the iterating over an array part so it just shows @post.title
, etc. So now my index just displays the last record in the Posts table with True on visible.
I then want to create an all posts archive page, that shows all of them regardless of visibility, so I created a new controller action:
(edited for clarity)
def archives
render :layout => 'posts'
@posts = Post.find(:all)
respond_to do |format|
format.html
format.xml { render :xml => @posts }
end
end
created a new named route:
map.archives 'posts/archives', :controller => 'posts', :action => 'archives'
and a view named archives.html.erb underneath views/posts.
Archives.html.erb looks exactly like the standard index.html.erb template that scaffolding creates, with a
<% for post in @posts %>
<tr>
<td><%=h post.title %></td>
...
</tr>
<% end %>
When I view this page in my browser, I get an error of
NoMethodError in Posts#archives
You have a nil object when you didn't expect it, you might have expected an isntance of Array, the error occurred while evaluating nil.each,
pointing to the line in the view (app/views/posts/archives.html.erb) that says
<% for post in @posts %>
so my understanding is that the data from the instance variable in the controller action archives
isn't passing into the view, so instead of an array of posts, I've got nil. I'm looking for a reason why, and what it is I'm doing wrong.
(Of course, if I put
<% @posts = Post.find(:all) %>
before the
<% for post in @posts %>
in the view, then it works just fine, but I know this is not what I should do.
All help, links to tutorials to straighten me out, etc is much appreciated.
(I'm doubtful it matters with something this simple, but I'm using Rails 2.2.2 and Ruby 1.8.6.)
Upvotes: 0
Views: 1311
Reputation: 749
This is correct:
respond_to do |format|
format.html { render :layout => 'posts' }
format.xml { render :xml => @posts }
end
end
@posts was not recognized by the view because it was instantiated after you rendered the view. 'render' should be the last executed line in an action.
Upvotes: 2