Separation in a Rails monolith: layouts, assets, and controllers

Consider introducing separation in your Ruby on Rails monolith with some simple techniques.

At TourExec, half the app is for the public, and the other half is for admins. They’re very different. Admin has a nav bar; public doesn’t. Admin uses Trix; public doesn’t. Public uses Stripe’s JavaScript library; admin doesn’t. The list goes on.

Everything lives in one Ruby on Rails app, and I like it that way. I’m one person maintaining TourExec, and separating out into multiple apps would create too much of a maintenance burden.

Here are some simple techniques to separate sections of your Rails monolith that serve different purposes.


Multiple layouts

The public section of TourExec is pretty minimal:

Booking a reservation on TourExec

Admin has a fuller layout, with a navigation bar:

Admin section of TourExec

I could continue using one application layout and conditionally include the navigation bar in admin. Instead, I use separate layouts for admin and public.

Create two layouts

  • app/views/layouts/admin.html.haml
  • app/views/layouts/public.html.haml

In each of your controllers, specify which layout to use


Use multiple JavaScript manifests

Public and admin use very different JavaScript. I want to avoid any risk of conflict between the two sections’ JavaScript code.

Separate the default manifest

Typically, in an app, you’d have one JavaScript manifest, like so:

  • /app/assets/javascripts/application.js

TourExec has two:

  • /app/assets/javascripts/admin.js
  • /app/assets/javascripts/public.js

Each manifest brings in appropriate JavaScript for that section. Here’s a peek at admin.js:

I place any custom JS for the admin section in app/assets/javascripts/admin, which is included by the manifest.

Tell Rails to precompile both manifests

To make Rails recognize both manifests so I can use them in layouts, I added this to /config/initializers/assets.rb:

Update your layouts to use each manifest

Our admin layout uses:

Our public layout uses:


Separate styles?

I could create separate CSS manifests, one for admin and one for public, but didn’t find it worth it. Instead, styles are namespaced with BEM and organized into topical folders in app/assets/stylesheets/. This provides solid separation and the ability to re-use styles throughout the app.


Namespace controllers

In TourExec, there’s a parent admin controller and a parent public controller. Other controllers inherit from one of them.

Here is a preview of the structure:

  • ApplicationController
    • AdminController
      • Admin::ToursController
    • PublicController
      • Public::ToursController

Remember when we specified which layout to use in each controller? Thanks to inheritance, you can specify the admin layout in the AdminController and the public layout in the PublicController, and their child controllers will use the layout as well.


Starting with a monolith

At first, your app may not require any of these techniques. As it grows, you may start introducing some separation to keep things sane. At sufficient scale, you may consider more formal approaches like component-based architecture.

Overall, I find it most efficient to keep apps monolithic for as long as possible, using simple techniques to keep things clean and maintainable. You’ll know when it’s not working anymore, and when a different architecture might be required. brings Rails job offers to you. Free for candidates. Salaries from $75,000 to $250,000. Sign up now!

2 thoughts on “Separation in a Rails monolith: layouts, assets, and controllers”

  1. What were the drawbacks to creating separate CSS manifests? And when you say “topical folders”, can you elaborate?

    1. Great question. I don’t see any drawbacks to separate style manifests. For my use case, there was a good amount of shared CSS and the CSS classes were already “namespaced.” I didn’t see a big advantage to separate manifests, so stuck with the Rails default of just one.

      I mistyped with topical folders. In reality, the CSS is organized into files named after top level CSS components. For instance, there’s “book.css” which has the CSS for the public-facing booking experience, whose classes start with “book__”. This is my interpretation (hopefully not butchering) of BEM. That’s just for my convenience, to be able to find classes quickly.

Leave a Reply