[Rails] ERB in JavaScript: buyer beware!

So you’ve been building your Rails application to the Twelve-Factor specification and putting all your config into environment variables like a good person.

Sometimes you need access to that config in JavaScript, such as a Google Analytics tracking code or a Stripe publishable key.

Rails has a nice-looking feature where you can name a file, e.g., app/assets/javascripts/stripe.coffee.erb and it will be processed by ERB before it’s handed to the CoffeeScript or JavaScript parser.

ERB considered harmful

Here’s the mistake I made. It was so tempting to include this environment data into my JavaScript this way. For example:

This works perfectly in development mode, when all your assets are compiled on the fly by the config.assets.debug parameter, but it’s a different story in production.

Assets need to be precompiled in production and this means the ERB and CoffeeScript parsing are run once, when your application is built. That means the value will be set to the current value of the environment variable at the time of build.

How I blew up my client’s staging environment

This wasn’t caught in my case because I had already set the environment variable in Heroku and then submitted dozens of new builds to my production environment which all dutifully precompiled the assets with the right environment variable.

And then my client came to deploy it to their staging environment, and pushed the build before setting the environment variable.

Boom! The variable was set to an empty string in the client’s staging environment and broken card entry forms & red faces were had all round. There isn’t even an easy way to trigger a rebuild in Heroku without making more changes to the git repo.

Gon to the rescue

The fix to this was, of course, to remove ERB from the equation altogether and use some runtime variable-passing such as the excellent gon:

From now on I’ll avoid ever using ERB templates inside the asset pipeline, and I’d encourage others to do the same!