In my previous post, we saw how to mount a sinatra application at a specific location for a regular application. But using Rack::Cascade, we can take that solution to a whole new height. That is :
- Put sinatra code in any of your regular Rails controllers.
- No need to mount at Sinatra at a specific URI.
- Have Sinatra work for any URI, gracefully fallback to Rails if no Sinatra method matches the path.
- Use your models/libraries etc. in both Rails and Sinatra.
So your controllers can look like :
1 2 3 4 5 6 7 8 |
class HomeController < ApplicationController get '/' do Item.count.to_s end def index end end |
and even :
1 2 3 4 5 6 7 8 9 |
class SiteController < ApplicationController get '/:name' do Site.find_by_name(params[:name]).html end def new end end |
And environment.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
RAILS_GEM_VERSION = '2.2.0' unless defined? RAILS_GEM_VERSION require File.join(File.dirname(__FILE__), 'boot') Rails::Initializer.run do |config| config.gem "sinatra" config.time_zone = 'UTC' config.action_controller.session = { :session_key => '_monkey_session', :secret => 'whatever' } end set :env, :production disable :run, :reload # Remove trailing slash from URIs reaching Sinatra before { request.env['PATH_INFO'].gsub!(/\/$/, '') if request.env['PATH_INFO'] != '/' } # Checking AR Connections back to the pool after { ActiveRecord::Base.clear_active_connections! } # Preload controllers with Sinatra code require 'home_controller' require 'site_controller' |
And most important, the rack setup file :
1 2 3 4 5 6 7 8 9 |
require File.dirname(__FILE__) + '/config/environment' require 'thin' app = Rack::Builder.new { use Rails::Rack::Static run Rack::Cascade.new([Sinatra.application, ActionController::Dispatcher.new]) }.to_app Rack::Handler::Thin.run app, :Port => 3000, :Host => "0.0.0.0" |
And start your server !
[lifo@219 monkey]$ ruby racked.rb






This is a nuke feature! Is there any way to run Merb application in the same way? Try to catch request by merb and fall back to rails?
@DEkart : Merb blindly copied a lot of things from Rails. They renamed classes for many cases, however there are very higher chances of a colision. YMMV PDI :)
ok. I’m already thinking about how to port my application developed with rails+merb to cascade application
Does this work with Rails 2.1?
It doesn’t work out of the box on Rails 2.1. But you can easily copy Rails’ rack handler from thin or use thin, and make it work.
Thanks for your wonderful posts about sinatra, I’ve found out that it is more than worth a look, actually I am trying to integrate it into an existing rails app to handle file uploads, but when i try to run my racked.rb it prompts me for an error?
undefined method `after’ for main:Object (NoMethodError)
when i have in my environment.rb setup this line of code:
running rails -v 2.2.0 / ruby -v ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9.5.0]
Its possible to run the thin server as described above. However instead of racked.rb script, its better to make a config.ru file in your rails root. Like this:
yourrailsapp/config.ru: require File.dirname(__FILE__) + '/config/environment' require 'thin' app = Rack::Builder.new { use Rails::Rack::Static run Rack::Cascade.new([Sinatra::Application, ActionController::Dispatcher.new]) }.to_app run app # This line is differentThen just run:
thin start -R config.ru <other server options>for example
thin start -R config.ru -e production -p 3000 -dwill run your rails app (including sinatra) in the background in production mode.
Then its just like running a proper server. Hooray !
Also, not sure why we need this bit:
# Checking AR Connections back to the pool after { ActiveRecord::Base.clear_active_connections! }I decided to leave it out. Seemed to work okay.
It’s also possible to blend a Sinatra application (or multiple Sinatra applications) with Rack::Builder and Rack::Cascade. Just include ‘sinatra/base’ instead of Sinatra, then create a module ModuleName that contains class ClassName < Sinatra::Base
Then you can mix and match by calling the appropriate ModuleName::ClassName for each of your Sinatra apps.