And the Greatest of These Is ... Rack Support

3,965 views

Published on

Presentation given at Railsconf 2009, about Rack support in Rails and the possibilities it presents.

Published in: Technology, Design
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,965
On SlideShare
0
From Embeds
0
Number of Embeds
86
Actions
Shares
0
Downloads
34
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide


  • 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

  • And the Greatest of These Is ... Rack Support

    1. And the Greatest of These Is... Rack Support Ben Sco eld – Viget Labs
    2. #?forben
    3. Application Templates
    4. Nested Attribute Assignment ickr: angelrays
    5. ActiveRecord::Base#touch ickr: jjjohn
    6. Rack
    7. def call(env) [ status, # 200 headers, # {quot;Content-Typequot; => quot;text/htmlquot;} body # [quot;<html>...</html>quot;] ] end
    8. request application response
    9. request middleware application middleware response
    10. Rack::Pro ler ickr: oberazzi
    11. Rack::MailExceptions ickr: warmnfuzzy
    12. Rack::Cache ickr: timpatterson
    13. rack::cascade Rack::Cascade ickr: _at
    14. Rack in Rails
    15. > 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
    16. > 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
    17. 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
    18. 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
    19. Metal ickr: lrargerich
    20. http://www.kiwibean.com/
    21. PLEASE testing metalBY STAND EXPAND: THIS IS ONLY A TEST
    22. METAL Sinatra
    23. Cool Tricks
    24. Rack::Bug ickr: catdancing
    25. requires </body>
    26. Progressive Caching
    27. Progressive Caching
    28. Progressive Caching
    29. class SessionsController < ApplicationController def create # ... session[:personalize] = { :logged_in => true, :quicklist => current_user.quicklist.episode_ids, :subscriptions => current_user.subscription_ids } end end
    30. class ChannelsController < ApplicationController caches_page :show def show @channel = Channel.find(params[:id]) end end
    31. $(document).ready(function() { $.getJSON('/personalize', function(data) { // identify quicklisted episodes $.each(data['quicklist'], function() { $('#episode_'+this).addClass('listed'); }); // switch navigation if (data['logged_in']) { $('#logged_in_nav').show(); } // etc. }); });
    32. class Personalizer def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/personalize/ [ 200, {quot;Content-Typequot; => quot;application/javascriptquot;}, env['rack.session'][:personalize].to_json ] else [404, {quot;Content-Typequot; => quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end
    33. class PullList def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/pulls/ [ 200, {quot;Content-Typequot; => quot;application/javascriptquot;}, [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]] else [404, {quot;Content-Typequot; => quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end standard 0.617 progressive 0.039 0.096
    34. class PullList def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/pulls/ [ 200, {quot;Content-Typequot; => quot;application/javascriptquot;}, [env['rack.session'][:pulls].to_json] ] else [404, {quot;Content-Typequot; => quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end standard 0.617 progressive 0.039 0.096 progressive v2 0.043 0.023
    35. DIY
    36. request middleware application middleware response
    37. Rack::Embiggener
    38. 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
    39. 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
    40. 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
    41. WARNING exception handling
    42. formerly: WARNING exception handling
    43. 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
    44. > 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
    45. 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
    46. 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
    47. 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
    48. Intangibles
    49. Thank You ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/bsco eld

    ×