Sinatra como Middleware

Not only is Sinatra able to use other Rack middleware, any Sinatra application can in turn be added in front of any Rack endpoint as middleware itself.

This endpoint could be another Sinatra application, or any other Rack-based application (Rails/Ramaze/Camping/…):

  1. When a request comes in, all before filters are triggered
  2. Then, if a route matches, the corresponding block will be executed
  3. If no route matches, the request is handed off to the wrapped application
  4. The after filters are executed after we've got a response back from the route or the wrapped app
Thus, our Sinatra app is a middleware.

Figura 33.2: La pila Rack
[scale=0.6]sinatra/rack_stack.png

[~/sinatra/sinatra-as-middleware]$ cat app.rb
require 'sinatra/base'
require 'haml'
require 'pp'

class LoginScreen < Sinatra::Base
  enable :sessions
  enable :inline_templates

  get('/login') { haml :login }

  post('/login') do
    if params[:name] == 'admin' && params[:password] == 'admin'
      puts "params = "
      pp params
      session['user_name'] = params[:name]
      redirect '/'
    else
      redirect '/login'
    end
  end
end

class MyApp < Sinatra::Base
  enable :inline_templates
  # middleware will run before filters
  use LoginScreen

  before do
    unless session['user_name']
      halt haml :denied
    end
  end

  get('/') do
    haml :cheer, :locals => { :name => session['user_name'] }
  end

  run!
end

__END__

@@ layout
!!!
%html
  %head
    %title Sinatra as Middleware
  %body
    %h1 Sinatra as Middleware
    = yield

@@ login
%form{:action=>'/login', :method=>'post'}
  %label{:for=>'name'} Name
  %input#name{:type=>"text",     :name=>"name", :autofocus => true }
  %br
  %label{:for=>'password'} Password
  %input#password{:type=>"password", :name=>"password"}
  %br
  %button#go{:type=>"submit",  :name=>"submit", :value=>"submit"} Click me!

@@ cheer
%h1
  Hello #{name}
  %br

@@ denied
%h1 
  Access denied, please 
  %a{:href=>'/login'}login.
Casiano Rodriguez León 2015-01-07