# Implicit Layout rendering in Rails

I love car-sharing services. It has allowed me to live car-free for the past three and a half years cutting down on maintenance, taxes, stress ... you name it. I can also book small cars for short rides, vans for moving stuff and larger, more comfortable cars for trips. It's amazing!

Today, we'll use a hypothetical car-share app to learn how to use Action View layouts to their fullest.

## Designing a car-sharing service

![A wireframe of a care-share app with 4 pages: a sign up page with a menu at the top with links to home, about, pricing sign up and log in, a logged in section with a menu to the right with links to a dashboard, search, bookings and my account and a content area to the right. A search page with no navigation and a lot of filters, search results and a map and finally a page for the car with several tabs for information, location, features and pictures.](https://cdn.hashnode.com/res/hashnode/image/upload/v1681613148058/81ef593b-a1ce-49d7-9c62-a8c8fb5c102d.png align="center")

This wireframe shows four basic screens our app will have that show different **areas** of our application that we will want to treat a bit differently.

## Conditional spaghetti 🍝

One way to achieve all of these different layouts is to squeeze everything into the default `application.html.erb` layout:

```erb
<!DOCTYPE html>
<html>
  <head><!-- ... --></head>
  <body>
    <%= if current_user.signed_in? %>
      <%= if current_page?(booking_rides_path) %>
        <%= yield %>
      <% end %>
      <%= if current_page?(dashboard_path) %>
        <%= yield %>
      <% else %>
        <%= yield %>
      <% end %>
    <% else %>
      <!-- Public nav-->
      <%= yield %>
    <% end %>
  </body>
</html>
```

Some pages require the user to log in, some don't. Some require their own specific set of rules and others share some visual aspects with others.

As you can probably tell, this will be hard to understand, extend and maintain. The issue with using a single layout is not just a matter of the ease of readability though. You could fix readability by turning most of this logic into several partials and call it a day. However this is a signal, and one you can train yourself to identify.

## Identifying the problem

All of those conditionals are telling you something: There are several concepts here that are claiming their own space. It's an architectural problem! To allow our app to grow and have the flexibility to use different layouts we need to give it proper foundations for it to scale.

As I see this wireframe I'm thinking:

* The app has public-facing, non-authenticated pages and other private, authenticated ones
    
* Within the authenticated pages:
    
    * There's a design that houses links to most sections of the app like the dashboard, bookings and my account
        
    * There is a special case when searching where all navigation disappears and the user is fully focused on the search and car-choosing experience.
        

## How does Rails find a layout

> Before diving into this, remember that Rails Guides are probably the best and probably most underutilised resource to learn about the framework. Most of what I'll tell you about here you can find in the [Layouts and Rendering in Rails](https://guides.rubyonrails.org/layouts_and_rendering.html#finding-layouts) guide.

As with most things Rails, the act of finding a **layout** that will wrap a **template/view** rendered by a **controller action** is based on conventions. In a fresh Rails app there is a single layout: `app/views/layouts/application.html.erb`. This is **the last fallback** the framework will use to display a template. Because in a new app there aren't other layouts Rails uses this one.

You can make your controllers render a different layout by doing so **explicitly or implicitly.**

If you haven't thought much about it and just use the `application.html.erb` layout then you are already using **implicit rendering** which relies on inheritance (more on this later).

On the other hand, you can tell Rails when to use a specific layout by:

* [specifying it in a controller](https://guides.rubyonrails.org/layouts_and_rendering.html#specifying-layouts-for-controllers)
    
* [Choosing it at runtime](https://guides.rubyonrails.org/layouts_and_rendering.html#choosing-layouts-at-runtime)
    
* Giving it as an argument to the `render` method
    

I use all of these in different situations but today we will focus on **implicit layout rendering leveraging** **inheritance** because this will help you not only organise your views but also give you the tools to build a better architectural foundation for your app.

### Authenticated or not authenticated

Let's focus on the first thing we identified. The app's needs are strikingly different for the authenticated and non-authenticated sections of it. It's almost as if they were two different apps and it is usually very obvious when looking at the design.

![Left: wireframe of the sign up page with a top navigation and a sign up form. The top links read home, about, pricing, sign up and log in. Right: wireframe of the app after the user has logged in with a left-hand side navigation with links to a dashboard, search, bookings and my account and a right-hand content area.](https://cdn.hashnode.com/res/hashnode/image/upload/v1681615508998/8895773b-acfb-446c-85a1-4047aef7952a.png align="center")

### Beyond the `ApplicationController`

The typical `ApplicationController` looks something like this:

```ruby
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
end
```

Before every controller action, you perform some type of user authentication. But, there is a portion of your app that is not authenticated and there are multiple pages that fit in that space like sign up, sign in, password recovery etc. For all of these pages, you would need to call `skip_before_action :authenticate_user!`. That's very cumbersome and also error-prone. So instead of skipping this action on every controller, why not create a specific controller that all public pages will use?

```ruby
# app/controllers/public/application_controller.rb
class Public::MainController < ApplicationController
  skip_before_action :authenticate_user!
end
```

I chose the name `Main` in this article to make it obvious that it's different from `Application` but you can name it whatever you want like:

* `Public::MainController`
    
* `Public::ApplicationController`
    
* `Public::BaseController`
    

Now every controller that is part of the **public** portion of your application and needs to skip authentication will be able to use this as its parent controller:

```ruby
class Public::RegistrationsController < Public::MainController
    def new
        # renders the sign up page
    end

    def create
        # ...
    end
end
```

At this stage, we still have a single `application.html.erb` layout. Whenever we visit our new registrations controller it will use that one because remember that this is the ultimate fallback that Rails uses if no other options are provided.

### Implicit Layouts

The benefit of this technique is that now we can rely on Rails' conventions to have a new, specific layout for your public controllers. We can create a `main.html.erb` layout under `app/views/layouts/public`. Notice the name: `main.html.erb`. It takes after the name of the controller which explains why in a fresh Rails app the default layout is named `application.html.erb.`

| Controller | Layout |
| --- | --- |
| `ApplicationController` | `application.html.erb` |
| `Public::MainController` | `public/main.html.erb` |

```plaintext
app/
  controllers/
    application_controller.rb
      public/
✨      main_controller.rb ⬅ Our new Controller
        registrations_controller.rb
  views/
    layouts/
      application.html.erb
      public/
✨      main.html.erb ⬅ 👀 A layout with matching name ✨
```

Rails chooses the layout to render a view in a cascading way based on the controller's inheritance chain. For the `Public::RegistrationsController` its chain looks like:

* `Public::RegistrationsController` that inherits from
    
* `Public::MainController` that inherits from
    
* `ApplicationController`
    

So when rendering the `Public::RegistrationsController#new` action, Rails will perform the following lookup:

|  | Controller | Layout | Found? |
| --- | --- | --- | --- |
| A specific layout for the controller | `Public::RegistrationsController` | `public/registrations.html.erb` | ❌ |
| A layout for its parent controller | `Public::MainController` | `public/main.html.erb` | ✅ |
| A layout for its grandparent controller | `ApplicationController` | `application.html.erb` | (it's there but it doesn't look for it because it already found one) |

## Git commit

![Left: wireframe of the sign up page with a top navigation and a sign up form. The top links read home, about, pricing, sign up and log in. Right: wireframe of the app after the user has logged in with a left-hand side navigation with links to a dashboard, search, bookings and my account and a right-hand content area.](https://cdn.hashnode.com/res/hashnode/image/upload/v1681615508998/8895773b-acfb-446c-85a1-4047aef7952a.png align="center")

This feels like a good place to commit. Through the wireframes and the spaghetti `application.html.erb` we saw earlier, we uncovered an important architectural pillar of our app: authenticated and non-authenticated pages have different needs and through different controllers and layouts we can convey those needs and give each an organised place to grow.

## On the next episode...

![A wireframe showing 3 screens of the authenticated portion of the app. The main navigation layout with links to the dashboard, search and booking pages, one of the search experience with search filters, results and a map and a third one, showing a specific car a user chose to view.](https://cdn.hashnode.com/res/hashnode/image/upload/v1681620169798/5bf461ca-4723-40fa-9ce0-aac055b6a04c.png align="center")

In the next article, we'll tackle the next piece of our puzzle: organising the authenticated portion of our app.

Stay tuned and let me know what you think!

---

## Off the Rails

This is the first article I posted after [announcing on Twitter](https://twitter.com/pinzonjulian/status/1645767023182643205?s=20) that I would start creating content to give back to the community and the response was amazing! Over one hundred people subscribed to my newsletter in the first couple of days. Thanks to everyone who subscribed, liked and retweeted!

Also, the car-sharing theme is part of this whole idea of designing beautiful cities and it's a topic a really enjoy. If you do too, take a look at this video from Not Just Bikes on car-sharing. This channel is AMAZING!

%[https://www.youtube.com/watch?v=OObwqreAJ48&t=605s]
