views:

37

answers:

1

I have a Rails-based site with a basic two-column layout. On the right is a sidebar with different (let's just say) vertical widgets. Depending on what page you visit, the widgets can be included, excluded, and in different order. For ex:

Main Page (Application)

PAGE CONTENT...

SIDEBAR

  • Widget A
  • Widget B
  • Widget C

Page X

PAGE CONTENT...

SIDEBAR

  • Widget D
  • Widget A
  • Widget C

Page Y

PAGE CONTENT...

SIDEBAR

  • Widget E
  • Widget A
  • Widget B
  • Widget C

Right now the way that I'm displaying the page-specific widgets is not very DRY. I'm creating a layout for each page, then copying and pasting the same HTML partials and widget partials over and over. For ex:

application.html.erb

<%= render :partial => 'shared/html_header' %>

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

    <%= render :partial => "shared/head" %>     

    <body>                        
        <div id="outer">

            <%= render :partial => 'shared/banner' %>
            <%= render :partial => 'shared/nav' %>

            <div id="main">
                <table cellpadding="0" cellspacing="0" border="0" style="width:100%;">
                  <tr style="vertical-align:top;">

                   <td style="width:759px;">
                    <%= render :partial => 'shared/content' %>
                  </td>

                        <td><%= image_tag("spacer.gif", :width => "5") %></td>

                        <td style="width:252px;">
                            <%= render :partial => 'shared/widget_a' %>
                            <%= image_tag("spacer.gif", :height => "10") %>

                            <%= render :partial => 'shared/widget_b' %>
                            <%= image_tag("spacer.gif", :height => "10") %>

                            <%= render :partial => 'shared/widget_c' %>
                            <%= image_tag("spacer.gif", :height => "10") %>

                        </td>
                    </tr>
                </table>
            </div>
            <%= render :partial => 'shared/footer' %>
        </div>
            <%= render :partial => 'shared/user_voice_widget_script' %>
            <%= render :partial => 'shared/google_analytics_script' %>
    </body> 
</html>

I basically just repeat this pattern for the other page layouts, but with the page-specific widgets. Doesn't seem too DRY.

I'm thinking there has to be a more efficient way to do this. Any suggestions?

+3  A: 

You can use a single layout file which defines the two column structure for all your pages and then use Rail's content_for helper to contextually populate your sidebar, depending on the page visited. Then the only page specific information is the sidebar detail, not the whole layout being repeated over and over.

In your (single) application layout:

<td style="width:252px;">
  <%= yield :sidebar %>
</td>

Somewhere in your pages:

<% content_for :sidebar do %>
  <%= render :partial => 'shared/widget_a' %>
  <%= image_tag("spacer.gif", :height => "10") %>

  ...

<% end %>

If enough of the widget combinations occur frequently together you could consider putting their render directives together into partials and using those in your content_for block.

The general technique is described here

bjg