views:

70

answers:

2

I have created a simple blog application with Ruby on Rails. The applications consists of two tables, posts and comments. Comments belongs_to :post and posts has_many :comments.

I created posts table with the following columns: title:string, body:text. I created the comments table with the following columns: body:text post_id:integer name:string email:string

In the /views/comments/index.html.erb display I would like to show a listing of all comments w/ the post title as well. Currently, the index view only displays post_id, body, name, email.

How do I replace the post_id column with the corresponding post title? Here is my code:

CommentsController Index action:

  def index
    @comments = Comment.all :order => "created_at DESC"
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @comments }
      format.json { render :json => @comments }
      format.atom
    end
  end

/views/comments/index.html.erb

<h1>Listing comments</h1>

<table>
  <tr>
    <th>Post</th>
    <th>Body</th>
  </tr>

<% @comments.each do |comment| %>
  <tr>
    <td><%=h comment.post_id %></td>
    <td><%=h comment.body %></td>
    <td><%=h comment.name %></td>
    <td><%=h comment.email %></td>
  </tr>
<% end %>
</table>

<br />
A: 

You can simply do <%=h comment.post.title %> to output the title of the post associated with the comment.

John Topley
I get the following error when I do that: undefined method `posts' for #<Comment:0x10420f990>. Do I also have to set something in the CommentsController Index action?
bgadoci
Did you try `comment.post.title` (singular) or `comment.posts.title`? The latter won't work.
John Topley
Did you do `comment.post.title`? Notice the singular post. I think you typed `comment.psots.title`.
Tony Fontenot
singular, just like you typed. Getting the same problem when I add anything after comment.post.whatever. BUT, when I just put <%=h comment.post %> it renders the actual post id record in the posts table (presumably), i.e. #<Post:0x1044dadc8>
bgadoci
so, just to clarify, when I add <%=h comment.post.title %>, I am getting an error saying that 'title' is an undefined method. If I change to body, I get the same 'undefined method' error but for body. It only seems to 'connect' to the post information when I leave it as <%=h comment.post %> in which case it t renders the actual post id record in the posts table (presumably), i.e. #<Post:0x1044dadc8>.
bgadoci
What output do you get if you run `script/console` and do `Post.column_names`?
John Topley
It gives me the following: ["id", "title", "body", "created_at", "updated_at"]
bgadoci
It is interesting, when I run the @comments = Comment.find(:all, :include => :post, :order => "created_at DESC") in the script/console it appears to list all column information except the title. After realizing that, I went back to the /views/comments/index.html.erb file and tried <%=h comment.post.body %> but that also gave me the undefined method for 'body' even though it was in the script/console output. Perhaps it is something having to do with routes or the model?
bgadoci
+1  A: 

If you have 100 comments, using comments.post.title with your code will result in 101 queries! See the Eager loading section on this docs page. Eager loading here will reduce it to 2.

def index
  @comments = Comment.find(:all, :include => :post, :order => "created_at DESC")
  # ...
end

In your views, you can access the post title as

<%= comment.post.title rescue "No post" %>

Edit: I'm using rescue "No Post" because you have some comments with post_id = nil and some comments with post_id that point to posts that no longer exist.

macek
I am still getting an error saying: undefined method `title' for nil:NilClass. Any ideas?
bgadoci
@bgadoci, try running `script/console` in your terminal. Do `c = Comment.find(1)` followed by `c.post.inspect`. What do you see?
macek
Ok, the first command returns this: #<Comment id: 1, post_id: nil, body: "test", created_at: "2010-04-10 04:49:54", updated_at: "2010-04-10 04:49:54", name: nil, email: nil>The second command returns "nil".
bgadoci
because perhaps the first comment was before I had everything set up, I ran c = Comment.find(25) and it returned this: #<Comment id: 25, post_id: 6, body: "test", created_at: "2010-04-11 19:41:13", updated_at: "2010-04-11 19:41:13", name: nil, email: nil>and then "nil" again for the second request.
bgadoci
@bgadoci, and what does `Post.find(6)` show?
macek
c = Post.find(6) returns: ActiveRecord: :RecordNotFound: Couldn't find Post with ID=6.
bgadoci
You should edit your question and add your models and create action wherever you're trying to associate the two. You may be creating your Post <-> Comment connections wrong if Comment 25 lists a post_id of 6 but there is no Post 6.
Eric Hill
@bgadoci, do you see the problem yet? You have comments with `post_id` = `nil` and some with `post_id` that points to Posts that no longer exist. You need to fix your data before you can expect it to perform the reliably. I updated my post to show another option.
macek
Man, I can't tell you how much I appreciate all the help. I am so new to all of this (programming and rails) that it is hard to get on here with such smart people. Thanks you so much that worked great.
bgadoci
@bgadoci, no problem. Never be afraid to ask questions. Just be thankful there's places like StackOverflow. I would've done anything for a resource like this when I was starting out :)
macek