views:

163

answers:

2

I have an index of users where I display the user name, location of user and a field called categories, which can range from zero to many items. I'm having trouble getting the categories to display properly. Here are my details:

User
has_many :user_categories
has_many :categories, :through => :user_categories

Categories
has_many :user_categories
has_many :users, :through => :user_categories

User_categories
belongs_to :user
belongs_to :category

In my user_categories table, there are three columns: id, user_id, category_id.
In my categories table, there are two columns: id and name.

In my user/index view, I have the following:

<% @users.each do |user| %>
  <%= link_to user.name, user %>  
  <%=h user.state %>
  <%=h user.categories %> ## This line is the problem
<% end %>

Where I've indicated the problem with my comment directly above, I've tried multiple variations, but somehow I'm missing it. Here are the variations that I've tried, and the results that they produce. Note that for testing, user #2 is the only one with a category that should display.

<%=h user.categories %>

displays: #<Category:0x3f40634>
Log shows:
UserCategory Load (0.4ms) SELECT * FROM "user_categories" WHERE ("user_categories".user_id = 2)

Category Load (0.4ms) SELECT "categories".* FROM "categories" INNER JOIN "user_categories" ON "categories".id = "user_categories".category_id WHERE (("user_categories".user_id = 2))

<%=h user.categories.name %> <-- Here I added .name at the end of the call

displays: category
log shows: App does not do a category load.

<%=h user.user_categories %>

displays: #<UserCategory:0x3e4d1a0>
log shows: UserCategory Load (0.4ms) SELECT * FROM "user_categories" WHERE ("user_categories"."user_id" = 2) AND ("user_categories".user_id = 2) LIMIT 1
Does not do a category load.

<%=h user.user_categories.find_by_user_id(user.id)  %>

produces same results as above.

Based on this, I think that <%=h user.categories %> is the one that makes the most sense, but I've tried every variation that I can think of and they all throw exceptions.

+2  A: 

The model definitions look correct. You may want to check your database to ensure you've used proper conventions for your ids. I was a concerned that you tried to display all categories in the "problem line". Try looping over them:

<% @users.each do |user| %>
  <%= link_to user.name, user %>  
  <%=h user.state %>
  <%=user.categories.each do |c| %>
    <%h c.name%>
  <%end%>
<% end %>
jrhicks
That worked. Any idea why my previous approach wasn't working? I'm not sure I understand what the problem was.
MikeH
This answer is right on the money. <Category:0x3f40634> is just the string representation of the Array object holding the @user's categories.
hgimenez
See my answer for further explanation - it wouldn't fit in a comment.
Greg Campbell
+1  A: 

The problem you were having is that in all three cases, you were attempting to display or operate on a collection of ActiveRecord objects. <%= h user.categories %> and <%= h user.user_categories %> will display the results of calling to_s on the collection, which gives the output (#<Category:0x3f40634> or #<UserCategory:0x3e4d1a0>) you noted. <%= h user.categories.name %> will display the result of calling name on the categories association.

jrhicks' answer works because he iterated over the categories and printed out the name of each one. See http://guides.rubyonrails.org/getting%5Fstarted.html#hooking-comments-to-posts for a similar example - in that case, they iterate over a post's comments.

Greg Campbell
Thanks. Appreciate the follow up.
MikeH