The document discusses Rack, a Ruby web server interface. It begins by explaining Rack's basic request/response cycle and common middleware components like Rack::Cache. It then covers integrating Rack into Rails applications and building custom middleware for tasks like exception handling and progressive caching. The document concludes by discussing some advanced Rack techniques and tools.
25. > rake middleware
use Rack::Lock
use ActionDispatch::Failsafe
use ActionDispatch::ShowExceptions, [true]
use ActionDispatch::Rescue, [#<Method: ...>]
use ActionDispatch::Session::CookieStore, [{...}]
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use Rack::Head
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
run ActionController::Dispatcher.new
26. > rake middleware
use Rack::Lock
use ActionDispatch::Failsafe
use ActionDispatch::ShowExceptions, [true]
use ActionDispatch::Rescue, [#<Method: ...>]
use ActionDispatch::Session::CookieStore, [{...}]
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use Rack::Head
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
run ActionController::Dispatcher.new
27. app = Rack::Builder.new {
use Rails::Rack::LogTailer unless options[:detach]
use Rails::Rack::Debugger if options[:debugger]
map quot;/quot; do
use Rails::Rack::Static
run ActionController::Dispatcher.new
end
}.to_app
28. Rails::Initializer.run do |config|
config.middleware.insert_before Rack::Head, Ben::Asplode
config.middleware.swap Rack::Lock, Ben::Lock
config.middleware.use Rack::MailExceptions
end
59. class Embiggener < Test::Unit::TestCase
def test_embiggener_should_embiggen_known_url
body = [quot;Hello! I'm at http://tinyurl.com/cjmhvaquot;]
assert_equal [quot;Hello! I'm at http://www.culann.comquot;],
Rack:: Embiggener.embiggen_urls(body)
end
def test_embiggener_should_embiggen_multiple_urls
body = [
quot;Hello! I'm at http://tinyurl.com/cjmhvaquot;,
quot;And I'm at http://tinyurl.com/cjmhvaquot;
]
assert_equal [
quot;Hello! I'm at http://www.culann.comquot;,
quot;And I'm at http://www.culann.comquot;
], Rack::Embiggener.embiggen_urls(body)
end
end
60. module Rack
class Embiggener
def self.embiggen_urls(original_body)
new_body = []
original_body.each { |line|
tinys = line.scan(/(http://(?:www.)?tinyurl.com/(.{6}))/)
new_body << tinys.uniq.inject(line) do |body, tiny|
original_tiny = tiny[0]
preview_url = quot;http://preview.tinyurl.com/#{tiny[1]}quot;
response = Net::HTTP.get_response(URI.parse(preview_url))
embiggened_url = response.body.match(/redirecturlquot; href=quot;(.*)quot;>/)[1]
body.gsub(original_tiny, embiggened_url)
end
}
new_body
end
# ...
end
end
61. module Rack
class Embiggener
# ...
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
headers.delete('Content-Length')
response = Rack::Response.new(
Rack::Embiggener.embiggen_urls(body),
status,
headers
)
response.finish
return response.to_a
end
end
end
64. Rack::Hoptoad*
* unofficial; thoughtbot is not responsible for this middleware; do not taunt rack::hoptoad; pregnant women should consult their doctors before using rack::hoptoad
65.
66. > rake middleware
use Rack::Lock
use ActionDispatch::Failsafe
use ActionDispatch::ShowExceptions, [true]
use ActionDispatch::Rescue, [#<Method: ...>]
use ActionDispatch::Session::CookieStore, [{...}]
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use Rack::Head
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
run ActionController::Dispatcher.new
67. Rails::Initializer.run do |config|
# ...
config.middleware.delete ActionDispatch::ShowExceptions
config.middleware.delete ActionDispatch::Rescue
config.middleware.use 'Rack::Hoptoad', 'my-hoptoad-api-key'
config.middleware.use 'Rack::ShowExceptions'
end
68. module Rack
class Hoptoad
def initialize(app, api_key)
@app = app
@api_key = api_key
end
def call(env)
@app.call(env)
rescue => exception
notify_hoptoad(exception, env)
raise exception
end
# ...
end
end
69. module Rack
class Hoptoad
def notify_hoptoad(exception, env)
headers = {
'Content-type' => 'application/x-yaml',
'Accept' => 'text/xml, application/xml'
}
url = URI.parse(quot;http://hoptoadapp.com/noticesquot;)
http = Net::HTTP.new(url.host, url.port)
data = {
:api_key => @api_key,
:error_message => quot;#{exception.class}: #{exception}quot;,
:backtrace => exception.backtrace,
:request => {},
:session => env['rack.session'],
:environment => env
}
response = http.post(
url.path,
stringify_keys(:notice => data).to_yaml,
headers
)
if response != Net::HTTPSuccess
# Hoptoad post failed
end
end
end
end
77. Thank You
ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/bsco eld
Editor's Notes
Lots of awesome things coming to Rails
standard API for all Ruby web frameworks
ruby-prof, benchmark application
replacement for exception notifier (but pay attention later)
not in rack core
ryan tomayko - earlier session?
chain sinatra/merb/other rack apps
file upload separate from main app
script/server
from railties/lib/commands/server.rb
Rails version of Rack::Cascade
talk about the poller example
unit testing for the individual metal action
integration testing for overall testing
Adam Wiggins talked about this in his session yesterday
135ms for hybrid, which is 21% of the standard
lame tests I employed showed the same or greater effect
66ms for hybrid v2, 10.6% of standard and 48% of hybrid
cooperation - multiple people contributing to each other, like Double Dragon!
this blonde guy is clearly in trouble, but if he had his buddy helping he’d be golden