Glenn Gillen

Simplifying ActiveRecord Connection Strings

Over the years I've gone to great lengths to avoid committing production passwords into version control. With Rails this has inevitably meant a number of different ways to ensure the database.yml was where it needed to be on the production servers, with the right credentials. Custom Capistrano recipes to create a new config when setting up a server, moving it into place after a deploy, it worked well enough but it's always felt a little heavy.

There's got to be a better way

There are a whole range of configuration settings that are environment dependent. Which database to connect to, what queues Resque workers should listen to, the Rack/Application environment mode. What we need is a standard way on each server to set these environment variables. Oh hang on, environment variables!

It's easy enough to either export an environment variable in a shell, or pass it in with the command like RACK_ENV=production rackup config.ru but a more complicated configuration like ActiveRecord requires doesn't quite work like that. It's expecting a Hash that defines the database adapter to use, username, password, the database, a host, and possibly a bunch of other options. We could probably serialise that back and forth between a Hash and something like JSON but it feels like a bit of a hack.

What would be better is if we could come up with a simple and uniform string format that could define how to locate any resource, including a database. I propose we call such a string a Uniform Resource Locator, or URL for short 😉

Using URLs to connect to databases

This isn't a new technique, other ORMs like Sequel have been doing this for years. It's just that ActiveRecord hasn't supported it, until now. I've created a gem that adds support for URL based connections to ActiveRecord, it's called activerecord_url_connections.

Add it to your Gemfile:

1
gem "activerecord_url_connections"

And now you can connect to your database by adding the following to an initializer (e.g., config/initializers/activerecord.rb):

1
ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"])

Now you can either export the DATABASE_URL environment variable in your app environment or set it when you start your app like so:

1
DATABASE_URL=postgres://localhost/myapp_production

No more juggling database.yml on production servers, no risk of checking sensitive credentials into version control.

Convention Over Configuration

Something still doesn't feel quite right about this approach though. Creating an initializer just to have that one line seems a bit needless, especially when it will be exactly the same in almost every app. So in much the same way Rails assumes a default connection to use if you don't provide one, so it will look to see if you've set DATABASE_URL and use it when available.

Stick with the conventions, and you'll not need to do anything beyond adding the gem and setting DATABASE_URL. Sweet!

But wait, there's more!

There's some further good news too. Firstly, for anyone using Heroku for hosting Rack apps that use ActiveRecord this means connection to your database will "just work" (it's not needed for Rails as Heroku create a database.yml file so the existing Rails behaviour will work). Secondly this change has made it into ActiveRecord for the 3.2 release so you'll only need this gem to backport the behaviour to previous releases.

Glenn Gillen

I'm an advisor to, and investor in, early-stage tech startups. Beyond that I'm an incredibly fortunate husband and father. Working on a developer-facing tool or service? Thinking about starting one? Email me and let me know or come to one of our days to help make it a reality.