Run Rails migrations automatically on Heroku

Heroku has a beta feature called release phase that allows you to run commands automatically when you deploy your app. The commands run in a separate process before your app is made available to users.

The most common use case for Rails developers to is automatically run database migrations on deploy.

There are other ways to auto-run migrations. In the past, I’ve done this in CI. Release phases are generally better, since they run migrations before your app is available to users. This way, you avoid serving your new release while migrations are still running.

This is awesome for handling failed migrations. If a migration fails, the new release is aborted without impacting users. Because Rails migrations operate within a transaction, your database will be just as it was before the failure.

A (very) quick walkthrough

Just about every app on Heroku has a Procfile at its root. Here’s what a typical Procfile with release phase looks like:

That’s. It. Migrations will run automatically each time you deploy, before the new release is available to users. This is Heroku at its seamless best.

So, if you have a Rails app on Heroku, check out release phase!

A case for decorators in Rails

Decorators, at the beginning of my Rails journey, seemed exotic and unnecessary.

Draper, a popular gem for decorators, calls them an “object-oriented layer of presentation logic to your Rails application.” I struggled to see the practical benefit.

A particular use case sold me on decorators’ benefits.

Use case: default field values

TourExec is a Rails app that helps businesses take reservations online.

When customers make a reservation, they see a friendly introduction from the business. TourExec provides a default introduction, which a business can override with a custom one.

Screen Shot 2016-08-06 at 7.13.49 PM

In the database, the business’s intro field is blank unless they’ve added a custom introduction. We need to show the default intro if the field is blank, or show the custom intro if the field is filled.

You might wonder why I don’t store the default right in the database. The default text is dynamic, based on the business’s name (which can change), and I want the flexibility to retroactively change the default text.

Option 1: Use conditionals in views

I could use conditionals within views to show either the default or the custom intro:

- if @business.intro.present?
  = @business.intro
- else
  We're excited to have you on a tour at [email protected]}!

This approach fell apart when I started building the form for businesses to update their intro message. I wanted businesses to see the default and be able to tweak or replace it.

Screen Shot 2016-08-06 at 7.18.33 PM

I had to hijack the form helper to show the default if the field was blank.

- f.input :intro, value: (
  (@business.intro.present? && @business.intro) ||
  "We're excited to have you on a tour at [email protected]}!")

This felt messy and unclear.

Option 2: Use the model

I considered overriding the “intro” method in the Business model to return the default if the intro was blank.

# app/models/business.rb

...

def intro
  (attributes["intro"].present? && attributes["intro"]) ||
  "We're excited to have you on a tour at #{name}!"
end

It felt wrong to add presentation logic to the model. If I wanted to use HTML in the default message, I’d have to use raw HTML in the model or bring in ActionView helpers, which have no place in a model.

Option 3: Use a decorator

Decorators handle “presentation logic” for your models. That is, if a model’s fields should be shown in a certain way, the decorator is responsible for making that happen. Draper is a great tool for quickly implementing decorators.

First, I installed the draper gem. Then, I created a decorator for businesses.

# app/decorators/business.rb

class BusinessDecorator < Draper::Decorator
  delegate_all

  def intro
    if object.intro.present?
      object.intro
    else
      "Book a tour with #{object.name} below!"
    end
  end
end

The decorator introduces an intro method on top of the model. It can reach into the model’s intro method with object.intro to grab the actual field value.

When I set @business in my controllers, I have to decorate the object:

@business = current_user.business.decorate

Now, in views, I can reference the field as I normally would.

= @business.intro

And I have to do absolutely nothing to my form helpers:

- f.input :intro

Decorators won!

For this implementation of default field values, decorators seem the best option. I’d love your thoughts and feedback in the comments.

More about decorators

Decorators can do a lot more, like:

  • Show a date field in a particular format throughout your app
  • Show a status field with particular language throughout your app
  • Anything else that involves showing data from your models in a particular way

Check out the Draper docs for more information. Draper doesn’t have a monopoly on decorators; it just makes them faster to implement with a proven approach.

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.