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