Skip to content
hirotaka edited this page May 9, 2012 · 3 revisions

This quickstart will get you going with Ruby and Sinatra on the Cedar stack. For Rails apps, please see the Rails 3 quickstart.

Prerequisites

  • Basic Ruby knowledge, including an installed version of Ruby 1.9.2, Rubygems, and Bundler.
  • Basic Git knowledge
  • Your application must run on Ruby (MRI) 1.9.2.
  • Your application must use Bundler.

Local Workstation Setup

Install the Heroku Toolbelt on your local workstation. This ensures that you have access to the Heroku command-line client, Foreman, and the Git revision control system.

Once installed, you use the heroku command from your command shell. Log in using the email address and password you used when creating your Heroku account:

:::term
$ heroku login
Enter your Heroku credentials.
Email: [email protected]
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.

Write Your App

You may be starting from an existing app. If not, here's a "hello, world" sourcefile you can use:

web.rb

:::ruby
require 'sinatra'

get '/' do
  "Hello, world"
end

Declare Dependencies With Bundler/Gemfile

Cedar recognizes an app as Ruby by the existence of a Gemfile. Even if your app has no gem dependencies, you should still create an empty Gemfile in order that it appear as a Ruby app.

In local testing, you should be sure to run your app in an isolated environment (via bundle exec or an empty RVM gemset), to make sure that all the gems your app depends on are in the Gemfile.

Here's an example Gemfile for the Sinatra app we created above:

Gemfile

:::ruby
source :rubygems
gem 'sinatra', '1.1.0'
gem 'thin'

Run bundle install to set up your bundle locally.

Declare Process Types With Foreman/Procfile

Cedar will recognize any app with a config.ru as a Rack app and generate a web process type for you. However, you'll get more control over how your app is executed if you explicitly declare your own web process type in a Procfile.

Here's a Procfile for the sample app we've been working on:

web: bundle exec ruby web.rb -p $PORT

If you're instead deploying a straight Rack app, here's a Procfile that can execute your config.ru:

web: bundle exec rackup config.ru -p $PORT

Now that you have a Procfile, you can start your application with Foreman:

:::term
$ foreman start

Your app will come up on port 5000. Test that it's working with curl or a web browser, then Ctrl-C to exit.

Store Your App in Git

We now have the three major components of our app: dependencies in Gemfile, process types in Procfile, and our application source in web.rb. Let's put it into Git:

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

Deploy to Heroku/Cedar

Create the app on the Cedar stack:

:::term
$ heroku create --stack cedar
Creating blazing-galaxy-997... done, stack is cedar
http://blazing-galaxy-997.herokuapp.com/ | [email protected]:blazing-galaxy-997.git
Git remote heroku added

Deploy your code:

:::term
$ git push heroku master
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 660 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)

-----> Heroku receiving push
-----> Ruby app detected
-----> Installing dependencies using Bundler version 1.1
       Checking for unresolved dependencies.
       Unresolved dependencies detected.
       Running: bundle install --without development:test --path vendor/bundle --deployment
       Fetching source index for http://rubygems.org/
       Installing daemons (1.1.3)
       Installing eventmachine (0.12.10) with native extensions
       Installing rack (1.2.2)
       Installing tilt (1.3)
       Installing sinatra (1.1.0)
       Installing thin (1.2.7) with native extensions
       Using bundler (1.1)
       Your bundle is complete! It was installed into ./vendor/bundle
-----> Discovering process types
       Procfile declares types -> web
       Default types for Ruby  -> console, rake
-----> Compiled slug size is 6.3MB
-----> Launching... done, v4
       http://blazing-galaxy-997.herokuapp.com deployed to Heroku

To [email protected]:blazing-galaxy-997.git
 * [new branch]      master -> master

Before looking at the app on the web, let's check the state of the app's processes:

:::term
$ heroku ps
Process       State               Command
------------  ------------------  ------------------------------
web.1         up for 10s          bundle exec ruby web.rb -p $PORT

The web process is up. Review the logs for more information:

:::term
$ heroku logs
2011-03-10T10:22:30-08:00 heroku[web.1]: State changed from created to starting
2011-03-10T10:22:32-08:00 heroku[web.1]: Running process with command: `bundle exec ruby web.rb -p 19037`
2011-03-10T10:22:33-08:00 app[web.1]: >> Thin web server (v1.2.7 codename No Hup)
2011-03-10T10:22:33-08:00 app[web.1]: >> Maximum connections set to 1024
2011-03-10T10:22:33-08:00 app[web.1]: >> Listening on 0.0.0.0:19037, CTRL+C to stop
2011-03-10T10:22:33-08:00 heroku[web.1]: State changed from starting to up

Looks good. We can now visit the app with heroku open.

Console

Cedar allows you to launch an interactive Ruby shell (bundle exec irb) attached to your local terminal for experimenting in your app's environment:

:::term
$ heroku run console
Running `console` attached to terminal... up, ps.1
irb(main):001:0>

By default, irb has nothing loaded other than the Ruby standard library. From here you can require some of your application files. Or you can do it on the command line:

:::term
$ heroku run console -r ./web

Rake

Rake can be run as an attached process exactly like the console:

:::term
$ heroku run rake db:migrate

Using a SQL Database

By default, non-Rails apps aren't given a SQL database. This is because you might want to use a NoSQL database like Redis or CouchDB, or (as in the case of our sample app above) you don't need any database at all. If you need a SQL database for your app, do this:

:::term
$ heroku addons:add shared-database

You must also add the Postgres gem to your app in order to use your database. Add a line to your Gemfile like this:

:::ruby
gem 'pg', '0.10.0'

Logging

By default, Ruby buffers its output to stdout. To take advantage of Heroku's realtime logging, you will need to disable this buffering to have log messages sent straight to Heroku's logging infrastructure. To disable this buffering add this to your config.ru:

:::ruby
$stdout.sync = true

Webserver

In the sample app used in this document, we included Thin in our Gemfile. Sinatra will use Thin to run when it's available in the environment. If you don't specify another webserver, Rack will fall back on the generic Webrick - which is fine for testing, but you should switch to Thin when your app is ready to go to 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. Port your app forward to Ruby 1.9.2 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. Not all gems work with Ruby 1.9 (see isitruby19 for information on a particular gem). If you hit an encoding error, you probably haven't fully tested your app with Ruby 1.9.2 in your local environment. Port your app forward to Ruby 1.9.2 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:

:::term
$ 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 you 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:

:::term
$ heroku run rake -T
Running `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:

:::term
$ 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

:::ruby
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.

Clone this wiki locally