Handling body element classes in Rails
By Andrew Bruce on Tuesday 20th May 11:31 PM
Setting the class attribute in the <body> element of a page can be really handy for CSS and JavaScript hooks. For example, if I wanted all pages with the class "checkout" to be laid out in a particular way, I could simply add the class to all the pages that were in the checkout phase, then add some CSS rules for ".checkout".
Rails' content_for method is useful for including sections of markup that don't fit in the main content of a page. But when it comes to setting classes for the body tag, content_for doesn't really cut the mustard.
First attempt
Here was my attempt at using content_for to set a template's body class:
<% content_for :body_attributes, 'class="checkout"' %>
Then, in my layout:
<body <%= yield :body_attributes %>>
This worked well until I wanted to add a class that indicated the current controller. Since I'd already explicitly set "class=" in each template, I couldn't easily modify the attribute to add further classes.
Helper to the rescue!
So I wrote a helper to do this better. Here it is!
def body_classes
@body_classes ||= [controller.controller_name]
end
As you can probably guess, the @body_classes instance variable defaults to an array with a single item: the name of the current controller. Handy for controller-wide CSS changes.
Here's how to call it from your layout.
<body class="<%= body_classes.join(' ') %>">
So now when you want to add an extra class to the default controller name, simply do the following from your template.
<% body_classes << 'checkout' %>
Since class names are separated by spaces, array manipulation is a lot more suitable for this task than content_for.
