Getting Started with Rails 3.x on Heroku
Last updated May 29, 2023
This article is a work in progress, or documents a feature that is not yet released to all users. This article is unlisted. Only those with the link can access it.
Table of Contents
This article is archived. It no longer receives updates and is here for historical reference only. We can’t guarantee that any statements made are still true or that the instructions still work. This version of Rails is no longer supported by Ruby core. If you’re starting a new application, we recommend you use the most recently released version of Rails.
This quickstart will get you going with Rails 3, deployed to Heroku. The latest version of Rails is Rails 7. If you’re starting a new app, you’ll probably want to use Getting Started with Rails 7. For Sinatra or other Ruby apps, please see Getting Started with Ruby on Heroku.
- Basic Ruby/Rails knowledge, including an installed version of Ruby 2.0.0, Rubygems, Bundler, and Rails 3.
- Basic Git knowledge
- Your application must run on Ruby (MRI) 2.0.0.
- A verified Heroku Account
- You are subscribed to the Eco dynos plan (recommended)
Local workstation setup
Once installed, you’ll have access to the
heroku command from your command shell. Log in using the email address and password you used when creating your Heroku account:
$ heroku login Enter your Heroku credentials. Email: email@example.com Password: Could not find an existing public key. Would you like to generate one? [Yn] Generating new SSH public key. Uploading ssh public key /Users/adam/.ssh/id_rsa.pub
Press enter at the prompt to upload your existing
ssh key or create a new one, used for pushing code later on.
We highly recommend using PostgreSQL during development. Maintaining parity between your development and deployment environments prevents subtle bugs from being introduced because of differences between your environments.
Write your app
Generate the app
You may be starting from an existing app. If not, a vanilla Rails 3 app will serve as a suitable sample app:
$ rails new myapp --database=postgresql $ cd myapp
If you’re upgrading an existing app, make sure you’re using PostgreSQL instead of SQLite3. Edit your
Gemfile and change this line:
In addition to using the
pg gem, you’ll also need to ensure the
config/database.yml is using the
postgresql adapter and not
config/database.yml file should look something like this:
development: adapter: postgresql encoding: unicode database: myapp_development pool: 5 username: myapp password: test: adapter: postgresql encoding: unicode database: myapp_test pool: 5 username: myapp password: production: adapter: postgresql encoding: unicode database: myapp_production pool: 5 username: myapp password:
Make sure to update the username and password for your database.
And re-install your dependencies (to generate a new
$ bundle install
In order to get the most out of the Heroku platform, include the
rails_12factor gem. This configures things like logging in your app to work on the platform.
gem 'rails_12factor', group: :production
You’ll need to update your dependencies using bundler.
$ bundle install
You can read more on this on our Ruby Support document.
Setting up the Asset Pipeline
config/application.rb set the following:
config.assets.initialize_on_precompile = false
Specify your Ruby Version
Since you’ll want development / production parity, you’ll want to specify the same version of Ruby locally that you have in production. We’ll be using the
ruby DSL introduced by Bundler. In your Gemfile add this to the bottom:
You can read more about specifying your Ruby Version.
Store your app in Git
$ git init $ git add . $ git commit -m "init"
Deploy your application to Heroku
Create the app on Heroku:
The Ruby buildpack auto-provisions a Mini Heroku Postgres database for your app. By default, apps use Eco dynos if you are subscribed to Eco. Otherwise, it defaults to Basic dynos. The Eco dynos plan is shared across all Eco dynos in your account and is recommended if you plan on deploying many small apps to Heroku. Learn more here. Eligible students can apply for platform credits through our Heroku for GitHub Students program.
$ heroku create --addons heroku-postgresql Creating severe-mountain-793... done, stack is heroku-18 http://severe-mountain-793.herokuapp.com/ | firstname.lastname@example.org:severe-mountain-793.git Git remote heroku added
Deploy your code:
$ git push heroku master Counting objects: 67, done. Delta compression using up to 4 threads. Compressing objects: 100% (52/52), done. Writing objects: 100% (67/67), 86.33 KiB, done. Total 67 (delta 5), reused 0 (delta 0) -----> Ruby/Rails app detected -----> Using Ruby version: ruby-2.0.0 -----> Installing dependencies using Bundler version 1.3.2 Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin --deployment Fetching gem metadata from https://rubygems.org/.......... Fetching gem metadata from https://rubygems.org/.. Installing rake (10.1.0) ... Installing uglifier (2.2.1) Your bundle is complete! It was installed into ./vendor/bundle Post-install message from rdoc: Depending on your version of ruby, you may need to install ruby rdoc/ri data: <= 1.8.6 : unsupported = 1.8.7 : gem install rdoc-data; rdoc-data --install = 1.9.1 : gem install rdoc-data; rdoc-data --install >= 1.9.2 : nothing to do! Yay! Cleaning up the bundler cache. -----> Writing config/database.yml to read from DATABASE_URL -----> Preparing app for Rails asset pipeline Running: rake assets:precompile Compiled jquery.js (9ms) (pid 735) Compiled jquery_ujs.js (0ms) (pid 735) Compiled application.js (32ms) (pid 735) Compiled application.css (2ms) (pid 735) Compiled jquery.js (5ms) (pid 735) Compiled jquery_ujs.js (0ms) (pid 735) Compiled application.js (16ms) (pid 735) Compiled application.css (1ms) (pid 735) Asset precompilation completed (19.16s) -----> Discovering process types Procfile declares types -> (none) Default types for Rails -> console, rake, web, worker -----> Compiled slug size: 34.0MB -----> Launching... done, v5 http://severe-mountain-793.herokuapp.com deployed to Heroku To email@example.com:severe-mountain-793.git * [new branch] master -> master
Visit your application
You’ve deployed your code to Heroku. You can now instruct Heroku to execute a process type. Heroku does this by running the associated command in a dyno - a lightweight container which is the basic unit of composition on Heroku.
Let’s ensure we have one dyno running the
web process type:
$ heroku ps:scale web=1
You can check the state of the app’s dynos. The
heroku ps command lists the running dynos of your application:
$ heroku ps === web: `bundle exec rails server -p $PORT` web.1: up for 5s
Here, one dyno is running.
We can now visit the app in our browser with
$ heroku open Opening severe-mountain-793... done
Dyno sleeping and scaling
By default, your app is deployed on an eco dyno. Eco dynos will sleep after a half hour of inactivity (if they don’t receive any traffic). This causes a delay of a few seconds for the first request upon waking. Subsequent requests will perform normally. Eco dynos also consume from a monthly, account-level quota of eco dyno hours - as long as the quota is not exhausted, all eco apps can continue to run.
To avoid dyno sleeping, you can upgrade to a Basic or Professional dyno type as described in the Dyno Types article. For example, if you migrate your app to a professional dyno, you can easily scale it by running a command telling Heroku to execute a specific number of dynos, each running your web process type.
View the logs
Heroku treats logs as streams of time-ordered events aggregated from the output streams of all the dynos running the components of your application. Heroku’s Logplex provides a single channel for all of these events.
For example, you can easily view information about your running app using one of the logging commands,
$ heroku logs 2011-03-10T11:10:34-08:00 heroku[web.1]: State changed from created to starting 2011-03-10T11:10:37-08:00 heroku[web.1]: Running process with command: `bundle exec rails server -p 53136` 2011-03-10T11:10:40-08:00 app[web.1]: [2011-03-10 19:10:40] INFO WEBrick 1.3.1 2011-03-10T11:10:40-08:00 app[web.1]: [2011-03-10 19:10:40] INFO ruby 2.0.0 (2013-06-27) [x86_64-linux] 2011-03-10T11:10:40-08:00 app[web.1]: [2011-03-10 19:10:40] INFO WEBrick::HTTPServer#start: pid=12198 port=53136 2011-03-10T11:10:42-08:00 heroku[web.1]: State changed from starting to up
Heroku allows you to run commands in a one-off dyno - scripts and applications that only need to be executed when needed - using the
heroku run command. Use this to launch a Rails console process attached to your local terminal for experimenting in your app’s environment:
$ heroku run rails console Running `bundle exec rails console` attached to terminal... up, ps.1 Loading production environment (Rails 3.2.14) irb(main):001:0>
Rake and Database Migrations
Rake can be run as an attached process exactly like the console:
$ heroku run rake db:migrate
Database migrations like above are not run automatically. If you have migrations to run, make sure to run
heroku run rake db:migrate after a deploy. You can find more on Rake commands.
By default, your app’s web process runs
rails server, which uses Webrick. This is fine for testing, but for production apps you’ll want to switch to a more robust webserver. On Cedar, we recommend Unicorn as the webserver. Regardless of the webserver you choose, production apps should always specify the webserver explicitly in the
Change the command used to launch your web process by creating a file called Procfile and entering this:
web: bundle exec unicorn -p $PORT -E $RACK_ENV
RACK_ENV to development in your environment and a
PORT to connect to. Before pushing to Heroku you’ll want to test with the
RACK_ENV set to production since this is the enviroment your Heroku app will run in.
$ echo "RACK_ENV=development" >>.env $ echo "PORT=5000" >> .env
You’ll also want to add
.env to your
.gitignore since this is for local enviroment setup.
$ echo ".env" >> .gitignore $ git add .gitignore $ git commit -m "add .env to .gitignore"
You’ll need to install the Unicorn gem by adding this to your Gemfile:
bundle install to install it locally.
Test your Procfile locally using
$ heroku local 17:04:16 web.1 | started with pid 20032 17:04:16 web.1 | I, [2013-03-13T17:04:16.857230 #20034] INFO -- : listening on addr=0.0.0.0:5000 fd=9 17:04:16 web.1 | I, [2013-03-13T17:04:16.857402 #20034] INFO -- : worker=0 spawning... 17:04:16 web.1 | I, [2013-03-13T17:04:16.858497 #20034] INFO -- : master process ready 17:04:16 web.1 | I, [2013-03-13T17:04:16.859851 #20038] INFO -- : worker=0 spawned pid=20038 17:04:16 web.1 | I, [2013-03-13T17:04:16.859978 #20038] INFO -- : Refreshing Gem list
Looks good, so press Ctrl-C to exit. Deploy your changes to Heroku:
$ git add . $ git commit -m "use unicorn via procfile" $ git push heroku
ps, you’ll see the web dyno uses your new command specifying Unicorn as the webserver:
$ heroku ps Process State Command ------------ ------------------ ------------------------------ web.1 starting for 3s bundle exec unicorn -p $PORT..
The logs also reflect that we are now using Unicorn:
$ heroku logs 2013-03-14T00:08:50+00:00 heroku[web.1]: State changed from created to starting 2013-03-14T00:08:53+00:00 heroku[web.1]: Starting process with command `bundle exec unicorn -p 38195 -E $RACK_ENV` 2013-03-14T00:08:54+00:00 app[web.1]: I, [2013-03-14T00:08:54.833013 #2] INFO -- : listening on addr=0.0.0.0:38195 fd=9 2013-03-14T00:08:54+00:00 app[web.1]: I, [2013-03-14T00:08:54.834767 #2] INFO -- : worker=0 spawning... 2013-03-14T00:08:54+00:00 app[web.1]: I, [2013-03-14T00:08:54.842064 #2] INFO -- : master process ready 2014-03-14T00:08:54+00:00 app[web.1]: I, [2013-03-14T00:08:54.843165 #5] INFO -- : worker=0 spawned pid=5 2013-03-14T00:08:54+00:00 app[web.1]: I, [2013-03-14T00:08:54.843441 #5] INFO -- : Refreshing Gem list 2013-03-14T00:08:56+00:00 heroku[web.1]: State changed from starting to up
See Deploying Rails Applications With Unicorn to learn how to configure Unicorn for production.
If you push up your app and it crashes (
heroku ps shows state
crashed), check your logs to find out what went wrong. Here are some common problems.
Failed to require a sourcefile
If your app failed to require a sourcefile, chances are good you’re running Ruby 1.9.1 or 1.8 in your local environment. The load paths have changed in Ruby 1.9 which also applies to Ruby 2.0.0. Port your app forward to Ruby 2.0.0 making certain it works locally before trying to push to Cedar again.
Ruby 1.9 added more sophisticated encoding support to the language which also applies to Ruby 2.0.0. If you hit an encoding error, you probably haven’t fully tested your app with Ruby 2.0.0 in your local environment. Port your app forward to Ruby 2.0.0 making certain it works locally before trying to push to Cedar again.
Missing a gem
If your app crashes due to missing a gem, you may have it installed locally but not specified in your
Gemfile. You must isolate all local testing using
bundle exec. For example, don’t run
ruby web.rb, run
bundle exec ruby web.rb. Don’t run
rake db:migrate, run
bundle exec rake db:migrate.
Another approach is to create a blank RVM gemset to be absolutely sure you’re not touching any system-installed gems:
$ rvm gemset create myapp $ rvm gemset use myapp
Runtime dependencies on development/test gems
If you’re still missing a gem when you deploy, check your Bundler groups. Heroku builds your app without the
test groups, and if your app depends on a gem from one of these groups to run, you should move it out of the group.
One common example using the RSpec tasks in your
Rakefile. If you see this in your Heroku deploy:
$ heroku run rake -T Running `bundle exec rake -T` attached to terminal... up, ps.3 rake aborted! no such file to load -- rspec/core/rake_task
Then you’ve hit this problem. First, duplicate the problem locally like so:
$ bundle install --without development:test ... $ bundle exec rake -T rake aborted! no such file to load -- rspec/core/rake_task
Now you can fix it by making these Rake tasks conditional on the gem load. For example:
begin require "rspec/core/rake_task" desc "Run all examples" RSpec::Core::RakeTask.new(:spec) do |t| t.rspec_opts = %w[--color] t.pattern = 'spec/**/*_spec.rb' end rescue LoadError end
Confirm it works locally, then push to Heroku.