Setting up Rails + Postgresql + Heroku on Mavericks

I spent hours today trying different ways of quickly and reproducibly provisioning a Mac for Rails + Postgresql development that could be deployed to Heroku.  What follows is, believe it or not, the easiest method I came up with.

This is a cheatsheet, not a tutorial.  I’m not going into much depth on what each command does, but if you’re just looking for a list of commands to get running quickly, you’re at the right place.

I tested these instructions against a stock installation of OS X Mavericks 10.9 in VMWare Fusion that had been patched up to 10.9.4 with Software Update.  Mavericks 10.9.4 ships with ruby 2.0.0p451.

This cheatsheet was compiled with information from https://devcenter.heroku.com/articles/getting-started-with-rails4 and other sources.

• First, create an account on Heroku, if you don’t have one already.

• Trigger the OS to install Developer Tools if you don’t already have them:

$ git
(Click Install)
(Agree to license agreement)

Installing just the Developer Tools is faster than installing Xcode if you don’t have/need it.

• Visit this page in Safari:

https://devcenter.heroku.com/articles/quickstart#step-2-install-the-heroku-toolbelt

• Click “Download Heroku Toolbelt for Mac OS X” and run the installer pkg file that it downloads.

• Install Homebrew:

$ ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
$ brew doctor

• Log in to Heroku:

$ heroku login
(Enter Heroku email)
(Enter Heroku password)

• Install postgresql:

$ brew install postgresql

• Install pg (postgresql) gem:

$ sudo ARCHFLAGS="-arch x86_64" gem install pg

• Start postgresql:

$ postgres -D /usr/local/var/postgres &

• Install Bundler:

$ sudo gem install bundler

• Install Rails:

$ sudo gem install rails --no-ri --no-rdoc
(When warned about conflicting rails executable, allow overwrite)

• Create a new postgresql-backed Rails app:

$ rails new myapp -d postgresql

• Create a barebones ‘welcome’ route in the app:

$ cd myapp
$ rails generate controller welcome

• Create app/views/welcome/index.html/erb with the editor of your choice, and insert the following content:

<h2>Hello World</h2>
<p>
The time is now: <%= Time.now %>
</p>

• Edit config/routes.rb and uncomment this line:

root 'welcome#index'

• Add this line to the end of Gemfile:

gem 'rails_12factor', group: :production

• Run Bundler to get the rails_12factor gem installed (required by Heroku):

$ bundle install

• Create a default database named after your username (a convenience for if you want to use a postgresql GUI like PG Commander later):

$ createdb

• Create dev and test databases for the Rails app:

$ createdb myapp_development
$ createdb myapp_test

• Edit config/database.yml and change the “production” section at the bottom to read like this:

production:
  url: <%= ENV['DATABASE_URL'] %>

Delete the database, username, and password lines from this section.  You can delete the line that begins with << too.

• At this point you should be able to run the app locally on the built-in server:

$ rails server
(visit url http://localhost:3000/)
(^C to stop the server)

• Create a git repo for the project:

$ git init
$ git add .
$ git commit -m "init"

• Create a Heroku app:

$ heroku create

Heroku will automatically assign your app a name consisting of a couple of words and a number.

• If you already have an SSH keypair, you can upload the public key through the Heroku dashboard, then, on your Mac, use ssh-add to make the private key available to ssh-agent.

If you don’t already have an SSH keypair, or would rather use a new one, let Heroku generate one:

$ heroku keys:add
(it asks if you want to generate one, say yes)

• Push git repository to Heroku:

$ git push heroku master
(if you get a warning that the authenticity of the host cannot be established, enter yes to continue)

• Confirm your app is now running on Heroku:

$ heroku open

At this point, Heroku is running the app on webrick, which is not suitable for production.

• To switch to the unicorn web server, add this line to the end of Gemfile:

gem 'unicorn'

• Then:

$ bundle install

• Create config/unicorn.rb with the following content (watch out for word-wrapping on the blog here):

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 15
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
  end

  after_fork do |server, worker|
    Signal.trap 'TERM' do
      puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
    end

    defined?(ActiveRecord::Base) and
      ActiveRecord::Base.establish_connection
  end

• Inform Heroku that you wish to use unicorn by creating a file called Procfile with this content:

web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb

• To test with the unicorn server locally, install Foreman:

$ sudo gem install foreman
(answer yes if it asks if you want to overwrite the existing executable)

• You can now start the unicorn web server with:

$ foreman start

Note that unicorn runs by default on port 5000 instead of webrick’s port 3000, so to test, visit http://localhost:5000/

• Stop unicorn with ^C.

• Commit changes to git repo:

$ git add .
$ git commit -m "added unicorn"

• Deploy to Heroku again:

$ git push heroku master

• Verify that Heroku is still serving a working app:

$ heroku open

• If you’d like extra confirmation that the app is now running atop unicorn, the server log should show something that looks like unicorn output:

$ heroku logs

And it’s just THAT EASY.  ;)