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.
We recommend using our low-cost plans to complete this tutorial. Eligible students can apply for platform credits through our new Heroku for GitHub Students program.
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.
Prerequisites
- 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
Install the Heroku CLI on your local workstation. This ensures that you have access to the Heroku command-line client, and the heroku local command.
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: adam@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.
Heroku provides you a PostgreSQL database for our app, so we’ll be using PostgreSQL as our local database as well. You will need to set this up locally.
Write your app
Generate the app
New 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
Existing App
If you’re upgrading an existing app, make sure you’re using PostgreSQL instead of SQLite3. Edit your Gemfile
and change this line:
gem 'sqlite3'
To this:
gem 'pg'
In addition to using the pg
gem, you’ll also need to ensure the config/database.yml
is using the postgresql
adapter and not sqlite3
. Your 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 Gemfile.lock
):
$ bundle install
Rails Plugins
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
Rails 3.1 introduced the Asset Pipeline to concatenate and minify or compress JavaScript and CSS assets. Heroku has a step in the build process to precompile your assets into your slug, so they’re readily available. To speed up asset precompiles, it’s recommended that you tell Rails to only partially load your app. Heroku also, does not provide the whole app environment to the build process, so this is required. In your config/application.rb
set the following:
config.assets.initialize_on_precompile = false
There are several options for invoking the Rails 3.1+ asset pipeline when deploying to Heroku. For full details please see the Rails 3.1+ Asset Pipeline on Heroku Cedar article.
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:
ruby '2.0.0'
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:
Using a dyno and a database to complete this tutorial counts towards your usage. Delete your app, and database as soon as you’re done to control costs.
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/ | git@heroku.com: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 git@heroku.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
.
$ 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
:
$ 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
Console
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.
Webserver
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 Procfile
.
Procfile
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
Set the 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:
gem 'unicorn'
Now run bundle install
to install it locally.
Test your Procfile locally using heroku local
:
$ 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
Check 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.
Troubleshooting
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.
Encoding error
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 development
or 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:
Rakefile
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.
Next steps
- Visit the Ruby category to learn more about deploying Ruby applications.
- Read How Heroku Works for a technical overview of the concepts you’ll encounter while writing, configuring, deploying and running applications.