DEV Community

Rails Designer
Rails Designer

Posted on • Edited on • Originally published at railsdesigner.com

Nested Layouts with Ruby on Rails

This article was originally published on Rails Designer


If you are familiar with Static Site Generators (like Jekyll, Middleman or Bridgetown) you might have used nested layouts. Within, say a "docs"-layout, you reference the "default" layout in the frontmatter. Something like this:

---
layout: default
---
Enter fullscreen mode Exit fullscreen mode

I often use a nested layout for my SaaS' settings page. It features a dedicated navigation for the many settings of the product. Unfortunately, Rails doesn't have a native way to nest layouts. But it's not too difficult to built ourselves!

The cleanest solution, and the one I use in my Rails apps, looks like this:

Create a base SettingsController:

# app/controllers/settings_controller.rb
class SettingsController < ApplicationController
end
Enter fullscreen mode Exit fullscreen mode

All other settings controllers will inherit from this (base) controller, eg. Settings::TeamsController < SettingsController. Because the SettingsController matches the layout name (“settings”), this layout will always be picked up correctly.

🧑‍🎨🎨 Need a way to up your Rails app's UI? Check out Rails Designer

Create a settings-layout:

# app/views/layouts/settings.html.erb
<div class="md:h-screen grid grid-cols-12 gap-4 md:gap-2 lg:gap-8">
  <%= component "navigation/settings", account: Current.account %>

  <div class="col-span-12 md:col-span-8 lg:col-span-9">
    <%= yield %>
  </div>
</div>

<⁠% parent_layout "application" %>
Enter fullscreen mode Exit fullscreen mode

You can add whatever component/HTML you need here (Rails Designer's Sidebar Navigation is a good match). Make sure to include the yield method!

Create a parent_layout helper

This helper is the important part that makes the nested layout work.

# app/helpers/layouts_helper.rb
module LayoutsHelper
  def parent_layout(layout)
    @view_flow.set(:layout, output_buffer)

    output = render(template: "layouts/#{layout}")

    self.output_buffer = ActionView::OutputBuffer.new(output)
  end
end
Enter fullscreen mode Exit fullscreen mode

The parent_layout method saves the current output, then renders the specified parent layout (eg. layouts/application), and finally sets this rendered output as the new output buffer to encapsulate the nested layouts.

Go read this article if you are interested in learning more how layouts work in Ruby on Rails (this article was extracted from it).

💡 Rails Designer has a collection of beautiful layouts ready for your Rails app. 👈

Top comments (1)

Collapse
 
railsdesigner profile image
Rails Designer

Other suggestion to use nested layouts, besides a settings page? Let me know! be🛎️