table headings in a partial template--possible? advisable?

Hey All,

I've got 2 views that show a tabular listing of my Person objects (one for people/index, and one for organizations/show). Here's what the organizations/show bit looks like:

  <% if @organization.people.count > 0 then %>   <h2>People from <%= h @organization.name %></h2>   <table>     <tr>       <th>Name</th>       <th>Organization</th>       <th>Phone</th>       <th>E-Mail</th>       <th>Typical Role</th>       <th>Notes</th>     </tr>     <%= render(:partial => "shared/person", :collection => @organization.people) %>   </table>   <p/>   <% end %>

As you can see--I'm starting the table & setting the headings in the partial-calling template. This meant that when I added an attribute to my Person class, I had to edit the 2 templates that called the partial. Not tragic or anything, but I'm guessing not optimal either.

So what's the DRY way to do this? Am I right that by the time we're in the partial template we're iterating through a collection, and it's too late to do anything pre-amble-y? Maybe a helper?

Also--bonus question: is there a graceful way of suppressing the printout of the Organization column when the partial is called from organizations/show? It's really redundant in that case...

Thanks much!

-Roy

Roy Pardee wrote:

Hey All,

I've got 2 views that show a tabular listing of my Person objects (one for people/index, and one for organizations/show). Here's what the organizations/show bit looks like:

  <% if @organization.people.count > 0 then %>   <h2>People from <%= h @organization.name %></h2>   <table>     <tr>       <th>Name</th>       <th>Organization</th>       <th>Phone</th>       <th>E-Mail</th>       <th>Typical Role</th>       <th>Notes</th>     </tr>     <%= render(:partial => "shared/person", :collection => @organization.people) %>   </table>   <p/>   <% end %>

As you can see--I'm starting the table & setting the headings in the partial-calling template. This meant that when I added an attribute to my Person class, I had to edit the 2 templates that called the partial. Not tragic or anything, but I'm guessing not optimal either.

So what's the DRY way to do this? Am I right that by the time we're in the partial template we're iterating through a collection, and it's too late to do anything pre-amble-y? Maybe a helper?

Also--bonus question: is there a graceful way of suppressing the printout of the Organization column when the partial is called from organizations/show? It's really redundant in that case...

Thanks much!

-Roy

Since you appear to be just listing people in both, then both should probably be run off the people controller index action. If you setup RESTful routes, you're two URLs would be /people (all people) and /organizations/42/people (just the people in org #42). Both urls will go to the people_controller index action. Then in your index action on that controller, you can do something like

def index   conditions = String.new   conditions += "organization_id = #{params[:organization_id]}"   @people = Person.find(:all, :conditions => conditions)    etc. etc. etc.

If you really do need to have two separate pages with different information, and both just happen to also list some people, then yes, moving that table off into some shared partial that both can use would be much DRYer and recommended. For instance, maybe /app/views/shared/_people_table.html.erb which from either view you could call with <%= render :partial => 'shared/people_table', :locals => {:people => @organization.people } %>

Have Fun!

Hmmm--interesting--thanks for the response!

So do I take it that it's *not* true that partials only ever iterate through the collection you pass in? You can do preface type stuff, like start up a <table> and define a header row? I was inferring that you couldn't from the fact that there's no explicit iteration happening in the partial--no "@collection.each do |item|" type stuff.

I suppose I should just test it--I was assuming I'd get a separate table for each Person if I put the <table></table> stuff in the partial.

Roy Pardee wrote:

Hmmm--interesting--thanks for the response!

So do I take it that it's *not* true that partials only ever iterate through the collection you pass in? You can do preface type stuff, like start up a <table> and define a header row? I was inferring that you couldn't from the fact that there's no explicit iteration happening in the partial--no "@collection.each do |item|" type stuff.

I suppose I should just test it--I was assuming I'd get a separate table for each Person if I put the <table></table> stuff in the partial.   

True, when you add the ":collection => argument" to your "render :partial", then it will iterate over each item in the collection, but you don't have to pass a collection if you only want to render it once. So, you could have one partial that sets up the table headers and is called from several pages, and it calls another partial that iterates over in items in the passed collection.

Got it--that makes perfect sense. Thanks! I'm tempted to just do one level of partial, so the header row & detail row code are all together. I think I'll start out that way & see if it's more or less painful over time.

So I guess if I want to suppress that 'organization' field in the table that winds up on organization/show, I can pass in another local var holding say, a list of fields to suppress, or a flag or some such thing...

Thanks!

-Roy