11. Overview
• Why Rack
• What’s Rack
• Rack Middleware
• Rails on Rack
• Example
• Q &A
12. Problems
• Ruby is popular
• Different web servers (app servers)
• Different web frameworks
• each framework has to write it’s own
handlers to different web servers
• Not only the handler
29. module Rack
class BeijingOnRails
def initialize(app)
@app = app
end
def call(env)
... ...
status, headers body = @app.call(env)
... ...
[status, header, body]
end
end
end
34. Rack - Specification
• Rack::Lint
specify "notices status errors" do
lambda {
Rack::Lint.new(lambda { |env|
["cc", {}, ""]
}).call(env({}))
}.should.raise(Rack::Lint::LintError).
message.should.match(/must be >=100 seen as integer/)
lambda {
Rack::Lint.new(lambda { |env|
[42, {}, ""]
}).call(env({}))
}.should.raise(Rack::Lint::LintError).
message.should.match(/must be >=100 seen as integer/)
end
38. Rack - Utilities
• Rackup
• a useful tool for running Rack
applications
• Rackup::Builder
• DSL to configure middleware and build
up applications easily
39. app = Rack::Builder.new do
use Rack::CommonLogger
use Rack::ShowExceptions
use Rack::ShowStatus
use Rack::Lint
run MyRackApp.new
end
Rack::Handler::Mongrel.run app, :Port => 8080
44. app = Rack::Builder.new {
use Rails::Rack::LogTailer unless options[:detach]
use Rails::Rack::Debugger if options[:debugger]
map "/" do
use Rails::Rack::Static
run ActionController::Dispatcher.new
end
}.to_app
46. Metal
• bypass some of the normal overhead of the
Rails stack
• specify certain routes and code to execute
when those routes are hit.
• avoid the entirety of ActionController
• Rails::Rack::Metal
• ActionController::MiddlewareStack
47. $ script/generate metal poller
class Poller
def self.call(env)
if env["PATH_INFO"] =~ /^/poller/
[200, {"Content-Type" => "text/html"},
["Hello, World!"]]
else
[404, {"Content-Type" => "text/html"},
["Not Found"]]
end
end
end
48. Rack::Metal
def call(env)
@metals.keys.each do |app|
result = app.call(env)
return result unless result[0].to_i ==
404
end
@app.call(env)
end
50. module Rack
class Runtime
def initialize(app, name = nil)
@app = app
@header_name = "X-Runtime"
@header_name << "-#{name}" if name
end
def call(env)
start_time = Time.now
status, headers, body = @app.call(env)
request_time = Time.now - start_time
if !headers.has_key?(@header_name)
headers[@header_name] = "%0.6f" % request_time
end
[status, headers, body]
end
end
end
56. Q &A
• Rack
• Ruby on Rails
• Caibangzi.com
• Mutual Fund & Investment
57. Why not simply string
• Ruby 1.8
• String was a collection of bytes
• String’s :each method iterated over lines of data
• Ruby 1.9
• String is now a collection of encoded data. (Raw
bytes and encoding information)
• :each has been removed from String and it’s no
longer Enumerable