Tuesday, February 15, 2011

Using Sinatra with Bundler to deploy on Heroku

I decided to try using sinatra for a small project I started the other day. I normally work in rails and host my personal projects on heroku. Since rails 3 came out I have also gotten hooked on bundler. I could not find any single source that documented how to use all of these together nicely. Here is how I got it to work.

Gemfile

The gemfile is pretty basic, set a source for gems and include the sinatra gem.
source :rubygems
gem 'sinatra'

config.ru

This is the rackup config file which sets the app up to run in rack.
require 'rubygems'
require 'bundler'

Bundler.require

require './myapp'

run MyApp

myapp.rb

This is the sinatra file. Note that I defined a class (MyApp). This is very important because our config.ru needs the class as a handle for the 'run MyApp' call. An alternative would be to use "run Sinatra::Application" in your config.ru file.
class MyApp < Sinatra::Base
  get '/' do
    'Hello world!'
  end
end

Running locally

First make sure rack is installed, then run the following commands in the root folder and the app should be up and running locally.
bundle install
rackup

Deploying to Heroku

Just run the following commands in the root folder and the app should be up and running on Heroku.
git init
git add .
git commit -m 'Initial version of MyApp'
heroku create
git push heroku master

Additional resources

5 comments:

Perceptes said...

It seems that the bundled gems are added to the load path without any explicit calls to Bundler. I have a Sinatra app running on Heroku, and my config.ru is simply:

require './app'
run Sinatra::Application

I explicitly require each gem as needed in app.rb and it all works.

nesquena said...

Using Bundler with Sinatra and deploying to Heroku is definately a great combination of technologies. I would also recommend checking out PadrinoRB (http://www.padrinorb.com/), a framework we built on top of Sinatra that augments it's functionality, gives you bundler support out of the box and a lot of other useful features like an admin interface.

KreeK said...

Hey Nathan,

Thanks for this. To get running locally I had to do:

bundle exec rackup

might help someone else who's stuck.

Travis said...

@Perceptes:

In fact, I had a problem using the method described in this post (ie require "bundler")

Errno::ENOENT - No such file or directory - /usr/ruby1.8.7/lib/ruby/gems/1.8/gems/bundler-1.0.7/lib/bundler/views/index.erb:

When I switched to simply:

require 'my_app.rb'
run Sinatra::Application

Everything started working again.

Josh said...

There is a bug where you say `require './myapp'`, because that means you want to require it relative to the directory you are currently in, but you actually want to require it relative to the config.ru file (ie if you ran this from a different directory, it would break).

Instead, you can `require File.dirname(__FILE__) + "/myapp"` which will require from the directory of config.ru

Or you can edit the load path so the directory is in it, and then require like normal, relative to that dir:
`$LOAD_PATH.unshift(File.dirname(__FILE__)); require 'app'`

Alternatively, when you run your server, you could do `$ bundle exec rackup -I . config.ru` which adds the current dir (the dot, the relative path to the root of your app) to the LOAD_PATH when you start the app. I like this best, it keeps the code cleanest, and you can put it in a rake task so you don't have to type all that stuff out. The problem is that Herkou doesn't currently give you that kind of control (I think Celadon Cedar does allow you to specify this command, but haven't tried)

Anyway, good write up, thanks for sharing :)