Simple (I'm sure) Question about Joins

I'm working on a into rails project in parallel with a book I'm reading.
I have 3 models/controllers that I'm trying to get to interact properly:
user, article, comment

Each article can have many comments, each comment is made by 1 user.
Currently I'm able to get the article to show the comment content and
the user_id of the commenter. But what I'm tying to do is get the
username of the commenter based on that user_id.

Here is part of my controller for the Article

def show
    @article = Article.find(params[:id])
    @user = User.find(@article.user_id)
    @comments = @article.comments
    impressionist(@snippet)
end

Each comment contains the following: content, user_id, article_id.

I can get the content and the user_id's associated to the article

<%= comment.content %>
<%= comment.user_id %>

This is a test comment user_id: 14
This is yet another thrilling test comment user_id: 15

What I'd like is comment.username so I can get the users name, but that
is throwing me for a loop. Making the connection between my users object
and the comments object.

I just don't know how to get the username associated with that user_id
from the users table. I've made it through my Rails Tutorial book,
however it didn't cover anything like this and a couple hours of
google-fu haven't yielded anything.

Any assistance is greatly appreciated!

Steve:

Assuming your many comments to one user relation is set-up properly, ask for cu = comment.user. Then <%= cu.username %> will work for you.

Doug

Douglas Lovell
www.wbreeze.com

Douglas Lovell wrote in post #1071218:

Steve:

Assuming your many comments to one user relation is set-up properly, ask
for cu = comment.user. Then <%= cu.username %> will work for you.

Doug

Douglas Lovell
www.wbreeze.com

Worked perfectly, thank you! :slight_smile:

I'm working on a into rails project in parallel with a book I'm reading.
I have 3 models/controllers that I'm trying to get to interact properly:
user, article, comment

Each article can have many comments, each comment is made by 1 user.
Currently I'm able to get the article to show the comment content and
the user_id of the commenter. But what I'm tying to do is get the
username of the commenter based on that user_id.

Here is part of my controller for the Article

def show
    @article = Article.find(params[:id])
    @user = User.find(@article.user_id)

You did not mention that the article has a user_id. I thought that
was comments that had user_id. However since it does have a user_id
then assuming you have set up the models correctly you should be able
to say
@user = @article.user

    @comments = @article.comments
    impressionist(@snippet)
end

Each comment contains the following: content, user_id, article_id.

I can get the content and the user_id's associated to the article

<%= comment.content %>
<%= comment.user_id %>

This is a test comment user_id: 14
This is yet another thrilling test comment user_id: 15

What I'd like is comment.username so I can get the users name, but that
is throwing me for a loop. Making the connection between my users object
and the comments object.

I just don't know how to get the username associated with that user_id
from the users table. I've made it through my Rails Tutorial book,
however it didn't cover anything like this and a couple hours of
google-fu haven't yielded anything.

Again you should just be able to use
comment.user.name

If that does not work show us the most important information, which is
how you have defined the relationships in the models (has_many,
belongs_to etc).

Colin

Alright so I changed my comment form snippet from:

<%= form_for(@comment, :html => { :class => "joinform" }) do |f| %>

To:

<%= form_for([@snippet, @snippet.comments.build]) do |f| %>

Which caused my comment form to finally work successfully, however the
following code now fails (this is my comment snippet)

<div class="comment_container">
  <%= gravatar_for comment.user, :size => 30 %> <span
class="username"><%= link_to comment.user.username, comment.user %>
commented <%= time_ago_in_words comment.created_at %></span>
  <div class="comment_content"><%= comment.content %></div>
</div>

What does work about this is the comment.user and comment.created_at
lines. Oddly enough, comment.content still shows the comment content.
And comment.user.username still yields the users username,
comment.user.email yields the commenters email, etc. However when
passing comment.user into anything now fails.

NoMethodError in Snippets#show

Showing
/Users/morri534/rails_projects/srclockr/app/views/comments/_comment.html.erb
where line #2 raised:

undefined method `email' for nil:NilClass

I feel like I'm so close to getting a working comment system, but I'm
missing one piece of the puzzle. I fixed the article comment box not
working, but now the comments wont display the user info associated with
them.

As usual, any help is greatly appreciated :slight_smile:

Here is some more code if it helps any:

class SnippetsController < ApplicationController
  before_filter :signed_in_user, :only => [:create]
  ...
  ...
  def show
    @snippet = Snippet.find(params[:id])
    @user = User.find(@snippet.user_id)
    @comments = @snippet.comments
    impressionist(@snippet)
  end

class Comment < ActiveRecord::Base
  attr_accessible :content, :snippet_id, :user_id
  belongs_to :snippet
  belongs_to :user

class Snippet < ActiveRecord::Base
  attr_accessible :content, :title, :description

  belongs_to :user
  has_many :comments

Since you have not quoted the previous message I have just wasted time
looking back through the thread to work out what this is about.
Remember this is a mailing list not a forum, though you may be using a
forum style interface

Alright so I changed my comment form snippet from:

<%= form_for(@comment, :html => { :class => "joinform" }) do |f| %>

To:

<%= form_for([@snippet, @snippet.comments.build]) do |f| %>

Which caused my comment form to finally work successfully, however the
following code now fails (this is my comment snippet)

<div class="comment_container">
  <%= gravatar_for comment.user, :size => 30 %> <span
class="username"><%= link_to comment.user.username, comment.user %>
commented <%= time_ago_in_words comment.created_at %></span>
  <div class="comment_content"><%= comment.content %></div>
</div>

What does work about this is the comment.user and comment.created_at
lines. Oddly enough, comment.content still shows the comment content.
And comment.user.username still yields the users username,
comment.user.email yields the commenters email, etc. However when
passing comment.user into anything now fails.

NoMethodError in Snippets#show

Showing
/Users/morri534/rails_projects/srclockr/app/views/comments/_comment.html.erb
where line #2 raised:

undefined method `email' for nil:NilClass

You appear to have provided lots of irrelevant information this time,
but not shown the code where the error is generated. I see that it is
in a partial, and that you are calling email on something that is nil.
Perhaps you have forgotten to pass the object to the partial.

Also have a look at the Rails Guide on debugging, which will show you
techniques that can be used to help in debugging the code.

Colin

Colin Law wrote in post #1071341:

Since you have not quoted the previous message I have just wasted time
looking back through the thread to work out what this is about.
Remember this is a mailing list not a forum, though you may be using a
forum style interface

I do apologize for that, I am quite new to the mailing list format of
communication (which is even harder to grasp while viewing the
discussion on a site called "ruby-forum").

comment.user.email yields the commenters email, etc. However when
passing comment.user into anything now fails.

NoMethodError in Snippets#show

Showing
/Users/morri534/rails_projects/srclockr/app/views/comments/_comment.html.erb
where line #2 raised:

undefined method `email' for nil:NilClass

You appear to have provided lots of irrelevant information this time,
but not shown the code where the error is generated. I see that it is
in a partial, and that you are calling email on something that is nil.
Perhaps you have forgotten to pass the object to the partial.

This is true, I'm having a very hard time conveying this issue. I have
spent countless hours trying to dig through debugging guides (including
the one referenced by you) yet I haven't been able to ge to the bottom
of this yet. As a direhard PHP programmer, getting my mind into Rails
mode is proving to be a challenge, even after reading a whole book and a
number of web resources on the topic.

So maybe this will help. If anyone is still willing to take a peek, I
have put the code on Github.

The comment form partial that was in place when the comment listings was
working is this:
https://github.com/uberamd/srclockr/blob/93c88fd17bb4ddde6c9a0eb88a87b2cfeefde897/app/views/shared/_comment_form.html.erb

When _comment_form.html.erb looked like that I was able to get comments
to display properly using this code:
https://github.com/uberamd/srclockr/blob/93c88fd17bb4ddde6c9a0eb88a87b2cfeefde897/app/views/comments/_comment.html.erb

However, when I changed _comment_form.html.erb to this code, the ability
to comment started working perfectly, however listing comments stopped
working:
https://github.com/uberamd/srclockr/blob/master/app/views/shared/_comment_form.html.erb

Whats odd (to me) is that I can call comment.user.email and get the
users email, but changing the _comment_form.html.erb file caused the
displaying of comments to break, which is not associated.

The comment, snippet, and user controller can be seen here:
https://github.com/uberamd/srclockr/tree/master/app/controllers

And the page where everything is brought together
(snippets/show.html.erb):
https://github.com/uberamd/srclockr/blob/master/app/views/snippets/show.html.erb

Hopefully this helps clarify the error I'm seeing. Despite my attempts
to debug, I'm just entirely lost as to why changing the partial for the
comment form broke the displaying of comments, though I'm sure its a
fairly basic error I'm encountering. Especially since, on the comments
partial, I'm still able to see the comment.content, just none of the
comment.user (who made the comment) information.

1 beer for anyone who can help guide this lost soul :slight_smile:

-Steve

Colin Law wrote in post #1071341:

Since you have not quoted the previous message I have just wasted time
looking back through the thread to work out what this is about.
Remember this is a mailing list not a forum, though you may be using a
forum style interface

I do apologize for that, I am quite new to the mailing list format of
communication (which is even harder to grasp while viewing the
discussion on a site called "ruby-forum").

comment.user.email yields the commenters email, etc. However when
passing comment.user into anything now fails.

NoMethodError in Snippets#show

Showing
/Users/morri534/rails_projects/srclockr/app/views/comments/_comment.html.erb
where line #2 raised:

undefined method `email' for nil:NilClass

You appear to have provided lots of irrelevant information this time,
but not shown the code where the error is generated. I see that it is
in a partial, and that you are calling email on something that is nil.
Perhaps you have forgotten to pass the object to the partial.

This is true, I'm having a very hard time conveying this issue. I have
spent countless hours trying to dig through debugging guides (including
the one referenced by you) yet I haven't been able to ge to the bottom
of this yet. As a direhard PHP programmer, getting my mind into Rails
mode is proving to be a challenge, even after reading a whole book and a
number of web resources on the topic.

So maybe this will help. If anyone is still willing to take a peek, I
have put the code on Github.

The comment form partial that was in place when the comment listings was
working is this:
https://github.com/uberamd/srclockr/blob/93c88fd17bb4ddde6c9a0eb88a87b2cfeefde897/app/views/shared/_comment_form.html.erb

When _comment_form.html.erb looked like that I was able to get comments
to display properly using this code:
https://github.com/uberamd/srclockr/blob/93c88fd17bb4ddde6c9a0eb88a87b2cfeefde897/app/views/comments/_comment.html.erb

However, when I changed _comment_form.html.erb to this code, the ability
to comment started working perfectly, however listing comments stopped
working:
https://github.com/uberamd/srclockr/blob/master/app/views/shared/_comment_form.html.erb

Whats odd (to me) is that I can call comment.user.email and get the
users email, but changing the _comment_form.html.erb file caused the
displaying of comments to break, which is not associated.

The comment, snippet, and user controller can be seen here:
https://github.com/uberamd/srclockr/tree/master/app/controllers

And the page where everything is brought together
(snippets/show.html.erb):
https://github.com/uberamd/srclockr/blob/master/app/views/snippets/show.html.erb

Hopefully this helps clarify the error I'm seeing. Despite my attempts
to debug, I'm just entirely lost as to why changing the partial for the
comment form broke the displaying of comments, though I'm sure its a
fairly basic error I'm encountering. Especially since, on the comments
partial, I'm still able to see the comment.content, just none of the
comment.user (who made the comment) information.

Sorry, much too much information again. Don't complicate it by
telling us about which bits do work or used to work, just pick out the
bit of code that is not working and show us that. Put debug code in
so that you can tell us what data is going in and explain what is
going wrong. We have not (or at least I do not) have time to wade
through all that information. If you have multiple problems then
start off with just one of them.

There will only be a dozen or so lines of code so just put it inline.

1 beer for anyone who can help guide this lost soul :slight_smile:

I am doing my best, but you must keep the question simple.

Colin

Alright. Short and simple this time. Here is the code for
snippets/show.html.erb (showing the article):

                     <div class="span4">
        <h1>Comments (<%= @snippet.comments.count %>)</h1>
        <hr>
        <% if signed_in? %>
          <%= render 'shared/comment_form' %>
        <% end %>
        <% if @snippet.comments.any? %>
          <%= render @comments %>
        <% else %>
        <p>There are no comments on this snippet.</p>
        <% end %>
      </div>

Here is comment.html.erb being showed by render @comments:

<div class="comment_container">
  <%= gravatar_for comment.user, :size => 30 %> <span
class="username"><%= link_to comment.user.username, comment.user %>
commented <%= time_ago_in_words comment.created_at %></span>
  <div class="comment_content"><%= comment.content %></div>
</div>

That is the code that isn't working and is giving the error. The only
thing that will display is comment.content.

And here is the log output. Seems to be properly getting the user data
for each comment, but comment.user isn't working. If I'm way off, let me
know again. At the very least I'm learning to better communicate issues
on this style of forum (sadly at the expense of peoples time).

   (0.1ms) SELECT COUNT(*) FROM "comments" WHERE
"comments"."snippet_id" = 4
  Rendered shared/_comment_form.html.erb (19.5ms)
  CACHE (0.0ms) SELECT COUNT(*) FROM "comments" WHERE
"comments"."snippet_id" = 4
  Comment Load (0.3ms) SELECT "comments".* FROM "comments" WHERE
"comments"."snippet_id" = 4 ORDER BY comments.created_at ASC
  User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" =
14 LIMIT 1
  User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" =
15 LIMIT 1
  CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 14
LIMIT 1
  Rendered comments/_comment.html.erb (27.5ms)
  Rendered snippets/show.html.erb within layouts/application (172.9ms)
Completed 500 Internal Server Error in 21602ms

ActionView::Template::Error (undefined method `email' for nil:NilClass):
    1: <div class="comment_container">
    2: <%= gravatar_for comment.user, :size => 30 %> <span
class="username"><%= link_to comment.user.username, comment.user %>
commented <%= time_ago_in_words comment.created_at %></span>
    3: <div class="comment_content"><%= comment.content %></div>
    4: </div>
  app/helpers/users_helper.rb:7:in `gravatar_for'
  app/views/comments/_comment.html.erb:2:in
`_app_views_comments__comment_html_erb___715147692_2186695040'
  app/views/snippets/show.html.erb:24:in
`_app_views_snippets_show_html_erb__1112126603_2190824420'

Colin Law wrote in post #1071379:

Alright. Short and simple this time. Here is the code for
snippets/show.html.erb (showing the article):

                     <div class="span4">
        <h1>Comments (<%= @snippet.comments.count %>)</h1>
        <hr>
        <% if signed_in? %>
          <%= render 'shared/comment_form' %>
        <% end %>
        <% if @snippet.comments.any? %>
          <%= render @comments %>
        <% else %>
        <p>There are no comments on this snippet.</p>
        <% end %>
      </div>

Here is comment.html.erb being showed by render @comments:

<div class="comment_container">
  <%= gravatar_for comment.user, :size => 30 %> <span
class="username"><%= link_to comment.user.username, comment.user %>
commented <%= time_ago_in_words comment.created_at %></span>
  <div class="comment_content"><%= comment.content %></div>
</div>

That is the code that isn't working and is giving the error. The only
thing that will display is comment.content.

And here is the log output. Seems to be properly getting the user data
for each comment, but comment.user isn't working. If I'm way off, let me
know again. At the very least I'm learning to better communicate issues
on this style of forum (sadly at the expense of peoples time).

   (0.1ms) SELECT COUNT(*) FROM "comments" WHERE
"comments"."snippet_id" = 4
  Rendered shared/_comment_form.html.erb (19.5ms)
  CACHE (0.0ms) SELECT COUNT(*) FROM "comments" WHERE
"comments"."snippet_id" = 4
  Comment Load (0.3ms) SELECT "comments".* FROM "comments" WHERE
"comments"."snippet_id" = 4 ORDER BY comments.created_at ASC
  User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" =
14 LIMIT 1
  User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" =
15 LIMIT 1
  CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 14
LIMIT 1
  Rendered comments/_comment.html.erb (27.5ms)
  Rendered snippets/show.html.erb within layouts/application (172.9ms)
Completed 500 Internal Server Error in 21602ms

ActionView::Template::Error (undefined method `email' for nil:NilClass):
    1: <div class="comment_container">

Put some debug in here to display (or log) comment.inspect (see the
Rails Guide on debugging), and also comment.user.inspect unless
comment.user is nil.

Colin

Colin Law wrote in post #1071405:

          <%= render @comments %>
commented <%= time_ago_in_words comment.created_at %></span>

15 LIMIT 1
  CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 14
LIMIT 1
  Rendered comments/_comment.html.erb (27.5ms)
  Rendered snippets/show.html.erb within layouts/application (172.9ms)
Completed 500 Internal Server Error in 21602ms

ActionView::Template::Error (undefined method `email' for nil:NilClass):
    1: <div class="comment_container">

Put some debug in here to display (or log) comment.inspect (see the
Rails Guide on debugging), and also comment.user.inspect unless
comment.user is nil.

Colin

Thanks for the continued replies, Colin.

<%= comment.inspect %> gave me:

#<Comment id: 1, content: "This is a test comment", user_id: 14,
snippet_id: 4, created_at: "2012-08-03 18:01:54", updated_at:
"2012-08-03 18:01:54">

And <%= comment.user.inspect %> gave me:

#<User id: 14, name: "Steve Morrissey", email: "uberamd@gmail.com",
username: "uberamd", isadmin: nil, isbanned: nil, created_at:
"2012-08-01 19:59:27", updated_at: "2012-08-02 19:39:18",
password_digest:
"$2a$10$nLyWoNjW3/7asFRYsfSKh.yEn824BVcoX2S6erXR3QxV...",
remember_token:
"73iKpBFDCXc4Imq46iABh7RUkG9n8M1HZR9c26b8AIZiFMgAZlt...">

So it appears, from my side of the table, that things are in order,
though clearly I'm missing something important. It looks, to me, like
comment.user has all the required info to display the gravatar_for image
(it just requires an email address) as well as comment.user.username and
comment.created_at. But alas, I am clearly wrong as it doesn't work.

Where are you getting gravatar_for from? Perhaps you are using a gem
that is not compatible with your version of rails.

Colin

Colin Law wrote in post #1071422:

Completed 500 Internal Server Error in 21602ms

Thanks for the continued replies, Colin.
username: "uberamd", isadmin: nil, isbanned: nil, created_at:
comment.created_at. But alas, I am clearly wrong as it doesn't work.

Where are you getting gravatar_for from? Perhaps you are using a gem
that is not compatible with your version of rails.

Colin

I thought about that, but then I tried to do something even easier. A
simple link to the commenters profile <%= link_to comment.user.username,
comment.user %> which gives:

NoMethodError in Snippets#show

Showing
/Users/smorriss/ruby_projects/srclockr/app/views/comments/_comment.html.erb
where line #4 raised:

undefined method `username' for nil:NilClass
Extracted source (around line #4):

1: <div class="comment_container">
2: <%= comment.inspect %>
3: <%= comment.user.inspect %>
4: <span class="username"><%= link_to comment.user.username,
comment.user %> commented <%= time_ago_in_words comment.created_at
%></span>
5: <div class="comment_content"><%= comment.content %></div>
6: </div>

So I'm basically very confused right now. It looks like comment.user has
everything I'd need to do that, yet nothing works. I can't even do a <%=
comment.user.username %> to display the users name, as it fails.

There is something horribly wrong somewhere. Which version of ruby
and of rails are you using? rails -v and ruby -v.
What do you see for inspect comment.user.username?

Colin Law

Colin Law wrote in post #1071427:

undefined method `username' for nil:NilClass

So I'm basically very confused right now. It looks like comment.user has
everything I'd need to do that, yet nothing works. I can't even do a <%=
comment.user.username %> to display the users name, as it fails.

There is something horribly wrong somewhere. Which version of ruby
and of rails are you using? rails -v and ruby -v.
What do you see for inspect comment.user.username?

Colin Law

It's starting to feel good that maybe, just maybe, I'm not losing my
mind here.

$ rails -v
Rails 3.2.6
$ ruby -v
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0]

undefined method `username' for nil:NilClass
Extracted source (around line #4):

1: <div class="comment_container">
2: <%= comment.inspect %>
3: <%= comment.user.inspect %>
4: <%= comment.user.username.inspect %>
5: <div class="comment_content"><%= comment.content %></div>
6: </div>

Steve Morrissey wrote in post #1071429:

Colin Law wrote in post #1071427:

undefined method `username' for nil:NilClass

So I'm basically very confused right now. It looks like comment.user has
everything I'd need to do that, yet nothing works. I can't even do a <%=
comment.user.username %> to display the users name, as it fails.

There is something horribly wrong somewhere. Which version of ruby
and of rails are you using? rails -v and ruby -v.
What do you see for inspect comment.user.username?

Colin Law

It's starting to feel good that maybe, just maybe, I'm not losing my
mind here.

$ rails -v
Rails 3.2.6
$ ruby -v
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0]

undefined method `username' for nil:NilClass
Extracted source (around line #4):

1: <div class="comment_container">
2: <%= comment.inspect %>
3: <%= comment.user.inspect %>
4: <%= comment.user.username.inspect %>
5: <div class="comment_content"><%= comment.content %></div>
6: </div>

Oddly enough I put a bandaid on this issue by moving the comment_form
partial from above the list of comments to under the list of comments.
This fixed everything. My guess would be that since the form has fields
like comment[content], it was creating an object called comment which
was conflicting with the partial that listed the comments out.