2. What is Rack?
Rack provides a minimal interface
“ between webservers supporting
Ruby and Ruby frameworks.
Transparently integrates in your existing
rails, sinatra apps
Helps you easily create a middleware
standalone application stack
3. Yeah! but... what is
Rack?
A Rack application is a Ruby object
that responds to call. It takes exactly
one argument, the environment and
returns an Array of exactly three
values: The status, the headers, and the
body.
9. What is a middleware?
Rack application that is designed
“ to run in conjunction with
another Rack application, which
acts as the endpoint
10. ...
Think of a Rack middleware as a filter
receiving the Rack environment for the
request from the previous middleware
Does some work with or on the
request's environment
Then calls the next middleware in the
chain
11. ...
The last Rack application in the
“ chain is the application itself
Any middleware in the chain can
return the Rack response itself, thus
preventing the rest of the middlewares
in the chain from executing
12. Installation
$... $ gem install rack
Successfully installed rack-1.2.1
1 gem installed
Installing ri documentation for rack-1.2.1...
Building YARD (yri) index for rack-1.2.1...
Installing RDoc documentation for rack-1.2.1...
13. Let's talk more Rack
status, headers, body = object
[200,
{ 'Content-Type' => 'text/html' }
'Hello World']
14. Stacking apps
m o d u l e MyModule
c l a s s Upcase
d e f initialize app
@app = app
end
d e f call env
p 'upcase'
status, headers, body =
[status, headers, [body.
end
end
end
15. ...
m o d u l e MyModule
c l a s s Reverse
d e f initialize app
@app = app
end
d e f call env
p 'reverse'
status, headers, body =
[status, headers, [body.
end
end
end
18. What happened?
A Decorator pattern happens
In OOP, the decorator pattern is
“ a design pattern that allows
new/additional behaviour to be
added to an existing object
dynamically
19.
20. Basic API
use(middleware, **args, &block) adds
a middleware to the stack
run(app) dispatches to an application
map(path, &block) constructs a
Rack::URLMap in a convenient way
21. Basic API - usage
example
r e q u i r e 'rack-validate'
use Rack::Validate
map '/hello' d o
run lambda d o |env|
[200,
{ 'Content-Type' => 'text/html'
'Hello World']
end
end
23. Basic optional usage -
Rack::Builder
Provides an optional DSL
app = Rack::Builder.new d o
map "/hello" d o
run lambda d o |env|
[200,
{ 'Content-Type' => 'text/html'
'Hello World']
end
end
end
24. Rack convenience
Wanna develop outside of existing
frameworks, implement your own
ones, or develop middleware?
Rack provides many helpers to create
Rack applications quickly and without
doing the same web stuff all over
27. use Rack::CommonLogger
Writes a log statement to STDOUT in the Apache
common log format for each request
use Rack::ShowExceptions
Renders a nice looking errors page for all
unhandled exceptions
use Rack::Lint
Ensures that your Rack application conforms to
the Rack spec. Rack::Lint will generate an
exception if the response of your application does
not meet the Rack spec
28. And many more
Rack::Auth::Basic
Rack::Session::Cookie
Rack::Sendfile
http://coderack.org/
http://rack.rubyforge.org/doc/
29. Is this testable?
Use your favorite framework
It provides Rack::MockRequest and
Rack::MockResponse
30. With bacon
Bacon is a small RSpec clone
“ weighing less than 350 LoC but
nevertheless providing all essential
features.
31. MockRequest
describe Rack::Static d o
root = File.expand_path(File.dirname(_ _ F I L E _ _
_
OPTIONS = {:urls => ["/cgi"], :root => root
@request =
Rack::MockRequest.new(
Rack::Static.new(DummyApp.new, OPTIONS
it "serves files" d o
res = @request.get("/cgi/test")
res.should.be.ok
res.body.should =~ /ruby/
end
end
32. MockResponse
describe Rack::Chunked d o
before d o
@env = Rack::MockRequest.
env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METH
end
should 'chunk responses with no Content-Length' d o
app = lambda { |env| [200, {}, ['Hello',
response = Rack::MockResponse.new(
*Rack::Chunked.new(app).call(@env))
response.headers.should.n o t .i n c l u d e 'Content-Le
n i
response.headers['Transfer-Encoding'].should
response.body.should.equal
"5rnHellorn1rn rn6rnWorld!rn0rnrn"
end
end
33. Why do we care?
Supported web servers
Mongrel, EventedMongrel,
SwiftipliedMongrel
WEBrick, FCGI, CGI, SCGI, LiteSpeed
Thin
34. These web servers include
handlers in their distributions
Ebb, Fuzed, Glassfish v3
Phusion Passenger (which is mod_rack
for Apache and for nginx)
Rainbows!, Unicorn, Zbatery
35. Any valid Rack app will run
the same on all these handlers,
without changing anything
36. Supported web
frameworks
Camping, Coset, Halcyon, Mack
Maveric, Merb,
Racktools::SimpleApplication
Ramaze, Rum, Sinatra, Sin
Vintage, Waves
Wee, … and many others.
37. Of course Ruby on Rails
Rails has adopted the Rack philosophy
throughout the framework
A Rails application is actually a
collection of Rack and Rails
middleware components that all work
together to form the completed whole
38. Listing the rails middleware
stack
$...(master) $ rake middleware
(in /home/chischaschos/Projects/salary-manager)
use ActionDispatch::Static
use Rack::Lock
use ActiveSupport::Cache::Strategy::LocalCache
use Rack::Runtime
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::RemoteIp
use Rack::Sendfile
use ActionDispatch::Callbacks
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use ActionDispatch::Head
use ActionDispatch::BestStandardsSupport
use Warden::Manager
use Sass::Plugin::Rack
run SalaryManager::Application.routes
39. Things to note
The Rack application being run with
the run directive at the end of the list of
middlewares is the Rails application's
routes
40. Rails controllers are
rack compliant
A controller declaration
c l a s s HomeController < ApplicationCont
d e f index
render :text => "I'm your home cont
end
end
42. Rack app from a controller
declaration
$ruby-1.8.7-p302 > app = HomeController.action :i
=> #<Proc:0xb6e26664@/home/chischaschos/.rvm/gem
ruby-1.8.7-p302 > app.respond_to? 'call'
=> true
ruby-1.8.7-p302 > status, headers, body = app.cal
=> [200, {"ETag"=>""d47cb2eec6f22cb9ff6fbb21cd34
ruby-1.8.7-p302 > body.body
=> "I'm yout home controller's body"
43. There are two different ways to
install Rack components into
your Rails application
1 - Either configure your Rack application as part
of your application's middleware stack
2 - Or you can route URI paths directly to the
Rack application from you application's routes
44. 1.1 - Installing a component into your
application
lib/average_time.rb
c l a s s AverageRuntime
@@requests = 0
@@total_runtime = 0.0
d e f initialize(app)
@app = app
end
d e f call(env)
code, headers, body = @app.call(env
@@requests += 1
@@total_runtime += headers['X-Runtime'
headers['X-AverageRuntime'] =
(@@total_runtime / @@requests).to_s
[code, headers, body]
end
45. 1.2 - Inserting the middleware
config/application.rb
r e q u i r e File.expand_path('../boot', _ _ F I L E _ _
r e q u i r e 'rails/all'
Bundler.r e q u i r e (:default, Rails.env)
r
m o d u l e RailsRackApp
c l a s s Application < Rails::Application
# starts the important part
config.autoload_paths += %W(#{config
config.middleware.insert_before Rack
"AverageRuntime"
# end the important part
config.encoding = "utf-8"
config.filter_parameters += [:password
end
end
46. 1.3 - Verifying middleware is in the
stack
$...$ rake middleware
(in /home/chischaschos/Projects/rack-testing/rails-rack-app)
use ActionDispatch::Static
use Rack::Lock
use AverageRuntime
use ActiveSupport::Cache::Strategy::LocalCache
use Rack::Runtime
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::RemoteIp
use Rack::Sendfile
use ActionDispatch::Callbacks
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use ActionDispatch::Head
use ActionDispatch::BestStandardsSupport
run RailsRackApp::Application.routes
47. 1.4 Testing our middleware
Look at X-Averageruntime: header
$...$ curl -I localhost:3000
HTTP/1.1 404 Not Found
Connection: Keep-Alive
Content-Type: text/html
Date: Fri, 05 Nov 2010 16:04:43 GMT
Server: WEBrick/1.3.1 (Ruby/1.8.7/2010-08-16)
X-Runtime: 0.312526
Content-Length: 621
X-Averageruntime: 0.312526
48. 2.1 - Routing to a rack application
lib/walking_arrow.rb
c l a s s WalkingArrow
ARROW = '=>'
@@spaces = 0
d e f call(env)
@@spaces += 1
[200, {'Content-Type' => 'text/plain'},
end
end
49. 2.2 - Add a route
lib/walking_arrow.rb
r e q u i r e 'lib/walking_arrow.rb'
RailsRackApp::Application.routes.draw
get 'home/index'
get 'walkingarrow' => WalkingArrow.new
end
53. Most sincere thanks to
http://rack.rubyforge.org/doc/
http://rails-nutshell.labs.oreilly.com
/ch07.html
http://rubylearning.com/blog/2010/09/21
/writing-modular-web-applications-
with-rack/?utmsource=twitterfeed&
utmmedium=twitter
And Mendo