post

Rails tip: handling a random sidebar
Rails tip: handling a random sidebar

As you may or may not know, I’m working on a new portfolio. And while designing out the pages, I realized that there are times when I want a sidebar and times when I don’t. “Oh, I know, I know! content_for, right?” Yes and no.

content_for is a drop-in solution when content is always there, but changes dynamically depending on the template. It can’t really be responsible for structural changes, but rather the content represented within a structure (read: content within the sidebar, not the sidebar itself). Yes, I know I can use content_for to show/hide the sidebar as a whole, but what about the case when it’s not present? There’d be an empty sidebar area that my content may want to take advantage of, which is where my problem lies.

I didn’t want a javascript solution to stretch out the content if no sidebar exists (no matter how unobtrusive); I wanted it to be rendered as intended for that view. See the problem? The sidebar does change depending on the template (content_for), but I also need to handle the case where I don’t want the sidebar at all by stretching my content out to the distance of the space the sidebar would have taken up. Leave it up to me to make an easy concept confusing.

So, now that I’ve detailed the problem, let me just say that I’m completely aware that this isn’t the only way to do this. I’m not saying this is the best way, either. But so far it’s working well for me.

I approached the problem thinking of two “mini-layout” situations, where it really boiled down to a couple of CSS classes for the content and a “to be or not to be” sidebar. My two CSS classes: ‘medium’ and ‘large’. As one might deduce, the ‘medium’ content would be the view with the sidebar, and the ‘large’ content would extend the full width with no sidebar. Here’s a template that would contain a sidebar:

<% content :medium do -%>
  <!-- markup for the standard content area -->
<% end -%>

<% sidebar do -%>
  <!-- markup/partial for the sidebar -->
<% end -%>

Pretty straight forward, huh? Just to be complete, here’s a template that would not have a sidebar where the content would eat up that extra “wasted” space:

<% content :large do -%>
  <!-- markup for the expanded content area -->
<% end -%>

Again, this may or may not be the best way, but here’s the snippet from the layout:

<%= content_tag :div, :class => @size do -%>
  <%= yield -%>
<% end -%>

<%= yield :sidebar -%>

Pretty simple. Here are the content and sidebar helpers:

def content(size, &block)
  @size = size.to_s and yield
end

def sidebar(&block)
  content_for(:sidebar, content_tag(:div, capture(&block), :id => 'sidebar'))
end

Now, if I could only solve the problem that is wanting to build too many applications at once, I’d be set.

Comments
01
18 Jan 2008 01:08 PM

Interesting, hadn’t thought of the block/helper thing.

For more complex layout changes, we have several layouts which just include the various components as partials.

For this sort of thing, I’d just use the fact that yield :sidebar returns nil if the sidebar hasn’t been content_for-ed. So you could just see what the yield has returned and decide from there whether to use the medium or large layout.

02
18 Jan 2008 01:09 PM

Oh yes, and I realise that my previous comment was what you were trying to avoid with the sentence “I’m not saying this is the best way, either. But so far it’s working well for me.”...

But for some reason I wrote it anyway :)

03
18 Jan 2008 02:10 PM

One thing that I knew I wanted to avoid was multiple layouts. The layouts change at the action level, rather than the controller level, so I didn’t want to clutter the controller code with specifying which layout I needed per action. To me, views are naturally the messy part of MVC, so I chose to keep those details there.

I see what you’re saying about checking for the content_for-ed sidebar. I’ve never checked what a yield returns before, but I’m assuming it’d be something like this?

css_class = yield(:sidebar).nil? ? 'large' : 'medium'

That’s definitely a more “automatic” way of setting the content width, and I think I like it. Thanks for the suggestion.

04
12 Jul 2008 08:08 PM

Thanks for the article, Ryan. I was just dealing with this exact problem (layout with a sometimes-present sidebar) and was nearing the solution you suggest in your last comment. But, your article helped me find the answer a bit quicker.

And, you don’t actually have to include .nil? ...it’ll automatically return a value of false if yield(:sidebar) evaluates to nil.




Please rewrite the image text in the SPAM field: Spam Protection

Preview

2008 by Ryan Heath | Get In Touch

flickr

DesolateInfinityLooking upDazedBlurred