Topic: display nested information correctly

Hey there--

So I'm well on my way with Rails, but every now and then hit walls that I just can't seem to get through. Here's one.

I have three different tables in my App, Issues, Categories, and Stories. This is for a magazine-content tracking app. The first step to linking things up right is that Categories have_many :stories, and that's been fine and works great! (thanks Ryan again for your help).

But a level of complication comes when I want to nest these things inside an issue. Here's where my brain's at on how this should work:

Because categories are the same from issue to issue (more or less), you wouldn't have an issue have_many :categories, because then your categories get caught in a single issue and you have to repeat yourself each issue. Bad UI. So instead, issues should have_many :stories. And yeah, that works great and I've hooked up the story form to allow assigning issues in there. Wonderful.

However, in an issue view, I want to see what categories are in an issue and what stories are inside those categories. The simple look at this is:

ISSUE
-category 1
---story 1
---story 4
-category 2
---story 5
---story 2
-category 3
---story 3

Now I've been able to set up the CATEGORY view to list exactly as described w/o the issue qualifier like so:

<% for category in @categories %>
                 <b><%= h(category.section) %></b><br />
        <% for story in category.stories %>
         <%= link_to story.title, :controller => "story_admin", :action => "show", :id => story.id %><br />
        <% end %>

Voila, works like a charm. BUT, I want this to work in the issue view instead.

Now, I can list stories in an issue no problem, by reproducing the code above, but swapping the issue calls where it's currently calling category.

And I can list the categories assigned to specific stories by calling story.category.section instead of story.title.

But what I can't figure out is now to list a category once, then have the stories assigned to it nest below, then list the next cat.... like in the above example.

Any help would be much apprecaited.

Re: display nested information correctly

The has_many :through option can help here.

# Issue
has_many :categories, :through => :stories

Then, you can loop through the given issue's categories and display the stories like this:

<% for category in @issue.categories %>
  ...
  <% for story in category.stories.find_all_by_issue_id(@issue.id) %>
    ...
  <% end %>
<% end %>

Does that do what you want?

Last edited by ryanb (2006-11-20 15:56:57)

Railscasts - Free Ruby on Rails Screencasts

Re: display nested information correctly

Does that do what you want?

Not so much. It's  giving me an NoMethodError:

"You have a nil object when you didn't expect it!
The error occured while evaluating nil.categories"

it's calling out this line as the problem:

<% for category in @issue.categories %>

Here's what I've got from what you gave:

class Issue < ActiveRecord::Base
  validates_presence_of :number
  has_many :stories
  has_many :categories, :through => :stories
end

that's the model. This is in the list view:

    <% for category in @issue.categories %>
    <%= h(category.section)%><br/>
    <% for story in category.stories.find_all_by_issue_id(@issue.id) %>
    <%=h (story.title )%> <br/>
<%end%>
    <%end%>

Re: display nested information correctly

You need to set the @issue instance variable in the controller. If you are setting the id in the URL you would do this:

def show
  @issue = Issue.find(params[:id])
end

Railscasts - Free Ruby on Rails Screencasts

Re: display nested information correctly

OK, now it's an all-new error! I've never seen this one before.

Before I get to this, since I'm doing all this in the list view, I stuck what you're syaing in def list instead of show. That might be the source of the problem, since the list view shows ALL the issues, and thusly doesn't do anything with the URL. Anyway, here's the error:

"ActiveRecord::RecordNotFound in Issue adminController#list"

"Couldn't find Issue without an ID"

Not sure what they're saying.

Re: display nested information correctly

Are you specifying the id of the issue you want in the URL? For example:

http://localhost:3000/issues/show/3

Of course insert your own controller/action.

BTW, if you want to display all issues on the page you would do things a bit differently:

# in controller
def list
  @issues = Issue.find(:all)
end

# in view
<% for issue in @issues %>
  <% for category in @issue.categories %>
    <% for story in category.stories.find_all_by_issue_id(issue.id) %>
      ...
    <% end %>
  <% end %>
<% end %>

# url
http://localhost:3000/issues/list

Railscasts - Free Ruby on Rails Screencasts