HABTM Reading Rows From Two Tables

I'm a newbie and loving rails but I'm stuck.

All I want to do is to be able to show in my "list.rhtml" view the
information between two tables who both have a HABTM relationship. So
this is what I have as follows.

I'm pretty new to Rails as well, but I think you need another for loop
to iterate over all the users. The experssion project.users refers to
a collection of users which doesn't have a first name. I would do
something like this:

<% for project in @projects %>
<%= project.title %><br>
  <% for user in project.users %>
    <%= user.first_name %>&nbsp<br>
  <% end %>
<% end %>

Hope that helps.

Hey Mike,

That totally worked.

Some additional thought...
You know for some reason I figured when you do a HABTM relationship
that an array would have both tables contained and you could access
them using just 1 loop. As I outlined in my attempted solution below:

<% for project in @projects %>
<%= project.title %><br>
<%= project.users.first_name %><br>
<% end %>

Your soultion works but it does require 2 loops. I just wonder do you
really need to use 2 loops. I'm trying to follow the whole DRY
principle and it seems too repeatative and it should be 1 loop.

Just a thought.

I'll just leave this posted to see if anyone else see other ways to do
it.

Mike Deck wrote:

Rather than trying to flatten the array Rails lets the user decide how
to handle it. This is a wise decision as many values may be
dynamically looked up during render.

For example, say you wanted to display the name of the who created the
user:

<% for project in @projects %>
<%= project.title %><br>
<%= project.user.first_name %><br>
<%= project.user.added_by.user.first_name %><br>
<% end %>

Since the relationship can be extremely complex and circular, there is
no way to determine what the user wants beforehand and it would in
inefficient to try.

Hey,

Re: Your example
So you have one loop pulling in information from two tables?
Are you suggesting this is how it should be done or should it be like 2
loops as shown in the above entry?

Or are you suggesting the data is too complex between the two tables
and you really can't pull it in at once because you get code like this.
<%= project.user.added_by.user.first_name %><br>

any feedback would be appriecated

askegg wrote:

Yes - this is one loop pulling information rom multiple tables (the
actual number depends on the underlying schema).

Unfortunately, here is no single answer to your question. Two loops
should be used when it is unclear how many (sub) entries there may be.
One loop is fine if you *know* there will only be one entry. It all
comes down to how your data is modeled.

If you pull all the possible information in a single table (like a
spreadsheet) the results could be enormous because the framework needs
to map all the possible combinations and collate them. If you have
*any* circular references the resulting table will be infinite.
Follow?

In you original example, one loop if fine if every project has one
user, which is almost certainly not the case.

Now that you further explained it, I understand a bit more. Thanks for
the extra feedback.

askegg wrote:

I don't think this violates DRY at all. Those two loops are doing two
different things, one displays projects and one displays users. But I
can see how this is a little cluttered. If you really want to get rid
of the second for loop you could use a partial template.

I'm not actually running the code I'm giving you here so there might be
a couple bugs, but this is the basic idea.

First of all lets change the way you're displaying the project list to
make it a little less trivial. Perhaps you want the user's names to be
in a list under each project. So the original template code looks like
this:

<% for project in @projects %>
<h2><%= project.title %></h2><br />
<ul>
<% for user in project.users %>
  <li><%= user.first_name %></li>
<% end %>
</ul>
<br />
<% end %>

Then you abstract the function of displaying a single user into another
rhtml file called _user.rhtml (the underscore prefix means it's a
partial template.) _user.rhtml would look something like this:

<li><%= user.first_name %></li>

Then you can change the original template to use the new partial
template. One of the nice features of using a partial is that it
allows you to pass in a collection to the render method which does the
iteration automatically for you. The new project list template would
look like this:

<% for project in @projects %>
<h2><%= project.title %></h2><br />
<ul>
  <%= render(:partial => "user", :collection => project.users)%>
</ul>
<br />
<% end %>

Is that simpler than the previous example? I don't know. You've used
the render method to take the nested loop out of your template, but
you've also added another file to project. To me the extra for loop is
still readable and I think it's overall less complex than adding
another file to maintain. If however you had multiple places in your
app where you were displaying lists of users this could be valuable
because then it really would be helping you adhere to the DRY principle.

Hey

Re: Partials
That is a very interesting technique for using partials. It does look
like a lot of work but I do have other areas where I need to bring up
that list.

So many new concepts to learn in ROR but this one is good.

I think I'll need to get the basics up and running and then go through
the code and start recfactoring it so it's clean.

thanks for the extra feedback