Last Updated: February 25, 2016
·
2.69K
· bryanmikaelian

Layout "hell" in Rails

We have a lot of layouts at Rethink Books. With sections of the app that are connected but very different, it makes for a challenge to manage layouts. The bigger challenge comes in when you start doing specific layouts for mobile tablet or phone. In our case, we have 3 layouts per section, each with their own set of CSS and JavaScript. It becomes a mess.

However, I recently read up on Rail's best practices for managing "layout hell" if you will and was faced with two options: partial the hell out of everything or use content_for blocks. We picked the latter and he is how it worked out (assume HAML):

Let's start with a root layout (application.html.haml is always a good choice).

// application.html.haml
!!! 5
%html
  %head
     = yield :title
     = yield :meta
     = yield :css 
     = yield :js
  %body
     = yield :navigation
     .container.with-standard-styling
       = yield :body

Pretty straight forward. But a lot of yields. What this lets you do is define sub layouts that share a common root. Before, we had a bunch of layouts that shared common functionality but the code was duplicated (remember have different layouts per major section of the app along with the device rendering the app). Now the duplication has been reduced but we can still customize each sub layout with whatever we need to. For example (three layouts)...

// store.iphone.haml
- content_for :css do
  = stylesheet_link_tag 'iphone.css.scss', 'small-nav.css.scss'
- content_for :body do
  %h1 I am an iPhone

// Render the root layout
= render file: 'layouts/application'

--

// store.html.haml
- content_for :css do
  = stylesheet_link_tag 'main.css.scss', 'nav.css.scss'
- content_for :body do
  %h1 I am just the website

// Render the root layout
= render file: 'layouts/application'

--

// social.html.haml
- content_for :navigation do 
  = render 'shared/facebook-style-nav'
- content_for :css do
  = stylesheet_link_tag 'social.css.scss'

- content_for :body do
  %h1 I follow the application layout but I am different

// Render the root layout
= render file: 'layouts/application'

By calling render file after the content_for blocks, the appropriate content gets sent up to the root layout and we get to use our core site styles.

We really struggled with this in the past but this appears to a solid way to handle this versus a bunch of partials. It has been much easier to manage now.

1 Response
Add your response

Does this behave well with, say, the Semantic-UI or another front-end framework classes? I'm trying layouting from Controllers and Namespaces and it's pure hell with those.

over 1 year ago ·