views:

50

answers:

3

I have my main application layout, but then I have an /account section of my site which has exactly the same layout as the application layout markupwise, except the /account pages have an added sidebar in the content area of the layout.

Rather than blatantly copy the application layout and create a nearly redundant "account" layout, I'd like to extend the application layout, adding the sidebar in the content area.

So I have something like this in my application layout:

<html>
<body>

<div id="content">

<%= yield %>

</div>

</body>
</html>

and I want

<html>
<body>

<div id="content">

  <div id="sidebar"></div>

  <%= yield %>

</div>

</body>
</html>

Is there a way to accomplish this without copying code?

+1  A: 

If your /account route is bound to the account controller, you can always have a fullfeatured layout with conditional part like this

render :template => "/shared/sidebar" if controller.controller_name == "account"

(I have to admit that it does not please the eye though)

hellvinz
+3  A: 

Often you'll have the same situation for other parts of the site in which case it may make sense to use nested layouts.

http://guides.rubyonrails.org/v2.3.8/layouts_and_rendering.html#using-nested-layouts

mark
A: 

You can have more than one yield in a layout, simply give the additional ones a name:

<html>
<body>
  <div id="content">
    <%= yield :sidebar %>
    <%= yield %>
  </div>
</body>
</html>

You can add HTML for that yield by using the content_for method

<% content_for :sidebar do -%>
  <div id="sidebar"></div>
<% end -%>

But you'll have to add that to every view you want to have a sidebar. Instead, create views/layouts/application_with_sidebar.html.erb

<% content_for :sidebar do -%>
  <div id="sidebar"></div>
<% end -%>

<%= render :file => 'layouts/application' %>

Further reading

If you'd prefer to keep the number of yields to a minimum, you can nest your layouts instead.

views/layouts/application.html.erb

<html>
<body>
  <div id="content">
    <%= yield(:with_sidebar) or yield %>
  </div>
</body>
</html>

views/layouts/application_with_sidebar.html.erb

<% content_for :with_sidebar do -%>
  <div id="sidebar"></div>
<% end -%>

<%= render :file => 'layouts/application' %>

controllers/accounts_controller.rb

class AccountsController < ApplicationController
  layout 'application_with_sidebar'
  ...
end
Adam Lassek
Then I'm throwing variables into the main, global layout that don't apply to all sections of the site. Just doesn't feel right. Thanks for the idea.
Chad Johnson
@Chad Nested Layouts like @mark suggested are probably the best alternative, then. It all depends on how often you need this markup to show up.
Adam Lassek