And the Greatest of These Is ... Space

1,594 views
1,524 views

Published on

Presentation given at Rails Underground; revision of earlier version given at Railsconf 2009.

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,594
On SlideShare
0
From Embeds
0
Number of Embeds
80
Actions
Shares
0
Downloads
28
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

And the Greatest of These Is ... Space

  1. 1. And the Greatest of These Is... Rack Support Ben Scofield – Viget Labs Saturday, July 25, 2009
  2. 2. Saturday, July 25, 2009
  3. 3. Application Templates Saturday, July 25, 2009
  4. 4. Nested Attribute Assignment flickr: angelrays Saturday, July 25, 2009
  5. 5. ActiveRecord::Base#touch flickr: jjjohn Saturday, July 25, 2009
  6. 6. DB Seeding flickr: richardthomas78 Saturday, July 25, 2009
  7. 7. Saturday, July 25, 2009
  8. 8. Saturday, July 25, 2009
  9. 9. Rack Saturday, July 25, 2009
  10. 10. Saturday, July 25, 2009
  11. 11. Saturday, July 25, 2009
  12. 12. def call(env) [ status, # 200 headers, # {"Content-Type" => "text/html"} body # ["<html>...</html>"] ] end Saturday, July 25, 2009
  13. 13. Saturday, July 25, 2009
  14. 14. request application response Saturday, July 25, 2009
  15. 15. request middleware application middleware response Saturday, July 25, 2009
  16. 16. Saturday, July 25, 2009
  17. 17. Rack::Profiler flickr: oberazzi Saturday, July 25, 2009
  18. 18. Rack::MailExceptions flickr: warmnfuzzy Saturday, July 25, 2009
  19. 19. Rack::Cache flickr: timpatterson Saturday, July 25, 2009
  20. 20. rack::cascade Rack::Cascade flickr: _at Saturday, July 25, 2009
  21. 21. Rack in Rails Saturday, July 25, 2009
  22. 22. Saturday, July 25, 2009
  23. 23. Saturday, July 25, 2009
  24. 24. Saturday, July 25, 2009
  25. 25. > rake middleware use Rack::Lock use ActionDispatch::ShowExceptions, [true] use ActionDispatch::Callbacks, [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 Saturday, July 25, 2009
  26. 26. > rake middleware use Rack::Lock use ActionDispatch::ShowExceptions, [true] use ActionDispatch::Callbacks, [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 Saturday, July 25, 2009
  27. 27. 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 Saturday, July 25, 2009
  28. 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 Saturday, July 25, 2009
  29. 29. # in config/initializers/middlewares.rb Rails::Initializer.run do |config| config.middleware.insert_before Rack::Head, Ben::Asplode ActionController::Dispatcher.middleware.insert_before 'Rack::Head', Appender config.middleware.swap Rack::Lock, Ben::Lock ActionController::Dispatcher.middleware.delete 'Rack::Lock' config.middleware.use Rack::MailExceptions ActionController::Dispatcher.middleware.use Prepender end Saturday, July 25, 2009
  30. 30. Metal flickr: lrargerich Saturday, July 25, 2009
  31. 31. http://www.kiwibean.com/ Saturday, July 25, 2009
  32. 32. Saturday, July 25, 2009
  33. 33. PLEASE testing metalBY EXPAND: STAND THIS IS ONLY A TEST Saturday, July 25, 2009
  34. 34. Saturday, July 25, 2009
  35. 35. METAL Sinatra Saturday, July 25, 2009
  36. 36. Cool Tricks Saturday, July 25, 2009
  37. 37. Rack::Bug flickr: catdancing Saturday, July 25, 2009
  38. 38. Saturday, July 25, 2009
  39. 39. Saturday, July 25, 2009
  40. 40. Saturday, July 25, 2009
  41. 41. Saturday, July 25, 2009
  42. 42. requires </body> Saturday, July 25, 2009
  43. 43. Progressive Caching Saturday, July 25, 2009
  44. 44. Progressive Caching Saturday, July 25, 2009
  45. 45. Progressive Caching Saturday, July 25, 2009
  46. 46. Saturday, July 25, 2009
  47. 47. class SessionsController < ApplicationController def create # ... session[:personalize] = { :logged_in => true, :quicklist => current_user.quicklist.episode_ids, :subscriptions => current_user.subscription_ids } end end Saturday, July 25, 2009
  48. 48. class ChannelsController < ApplicationController caches_page :show def show @channel = Channel.find(params[:id]) end end Saturday, July 25, 2009
  49. 49. $(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. }); }); Saturday, July 25, 2009
  50. 50. class Personalizer def self.call(env) if env["PATH_INFO"] =~ /^/personalize/ [ 200, {"Content-Type" => "application/javascript"}, env['rack.session'][:personalize].to_json ] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end end end Saturday, July 25, 2009
  51. 51. Saturday, July 25, 2009
  52. 52. Saturday, July 25, 2009
  53. 53. Saturday, July 25, 2009
  54. 54. Saturday, July 25, 2009
  55. 55. class PullList def self.call(env) if env["PATH_INFO"] =~ /^/pulls/ [ 200, {"Content-Type" => "application/javascript"}, [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end end end standard 0.617 progressive 0.039 0.096 Saturday, July 25, 2009
  56. 56. class PullList def self.call(env) if env["PATH_INFO"] =~ /^/pulls/ [ 200, {"Content-Type" => "application/javascript"}, [env['rack.session'][:pulls].to_json] ] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end end end standard 0.617 progressive 0.039 0.096 progressive v2 0.043 0.023 Saturday, July 25, 2009
  57. 57. DIY Saturday, July 25, 2009
  58. 58. request middleware application middleware response Saturday, July 25, 2009
  59. 59. Rack::Embiggener Saturday, July 25, 2009
  60. 60. Saturday, July 25, 2009
  61. 61. class Embiggener < Test::Unit::TestCase def test_embiggener_should_embiggen_known_url body = ["Hello! I'm at http://bit.ly/31IqMl"] assert_equal ["Hello! I'm at http://cnn.com"], Rack:: Embiggener.embiggen_urls(body) end def test_embiggener_should_embiggen_multiple_urls body = [ "Hello! I'm at http://bit.ly/31IqMl", "And I'm at http://bit.ly/31IqMl" ] assert_equal [ "Hello! I'm at http://cnn.com", "And I'm at http://cnn.com" ], Rack::Embiggener.embiggen_urls(body) end end Saturday, July 25, 2009
  62. 62. module Rack class Embiggener def self.embiggen_urls(original_body, login, key) new_body = [] original_body.each { |line| bits = line.scan(/(http://bit.ly/(.{6}))/) new_body << bits.uniq.inject(line) do |body, bit| original_bit, hash = *bit new_url = embiggened_url(hash, login, key) body.gsub(original_bit, new_url) if new_url end } new_body end # ... end end Saturday, July 25, 2009
  63. 63. module Rack class Embiggener # ... def self.embiggened_url(hash, login, key) url = [ "http://api.bit.ly/expand?version=2.0.1", "shortUrl=http://bit.ly/#{hash}", "login=#{login}", "apiKey=#{key}" ].join('&') response = JSON.parse(Net::HTTP.get_response(URI.parse(url))) if response['statusCode'] = 'OK' embiggened_url = response['results'][hash]['longUrl'] end end # ... end end Saturday, July 25, 2009
  64. 64. module Rack class Embiggener # ... attr_accessor :api_login, :api_key def initialize(app, api_login, api_key) @app = app @api_login = api_login @api_key = api_key end def call(env) status, headers, body = @app.call(env) headers.delete('Content-Length') response = Rack::Response.new( Rack::Embiggener.embiggen_urls(body, api_login, api_hash), status, headers ) response.finish return response.to_a end end end Saturday, July 25, 2009
  65. 65. module Rack class Embiggener def self.embiggen_urls(original_body, login, key) new_body = [] original_body.each { |line| bits = line.scan(/bit:(w+?)/) new_body << bits.uniq.inject(line) do |body, bit| hash = bit.first original_bit = "bit:#{hash}" new_url = embiggened_url(hash, login, key) body.gsub(original_bit, new_url) if new_url end } new_body end # ... end end Saturday, July 25, 2009
  66. 66. module Rack class Embiggener # ... def self.embiggened_url(hash, login, key) url = [ "http://api.bit.ly/expand?version=2.0.1", "hash=#{hash}", "login=#{login}", "apiKey=#{key}" ].join('&') response = JSON.parse(Net::HTTP.get_response(URI.parse(url))) if response['statusCode'] = 'OK' embiggened_url = response['results'][hash]['longUrl'] end end # ... end end Saturday, July 25, 2009
  67. 67. WARNING exception handling Saturday, July 25, 2009
  68. 68. formerly: WARNING exception handling Saturday, July 25, 2009
  69. 69. 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 Saturday, July 25, 2009
  70. 70. Saturday, July 25, 2009
  71. 71. > rake middleware use Rack::Lock use ActionDispatch::ShowExceptions, [true] use ActionDispatch::Callbacks, [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 Saturday, July 25, 2009
  72. 72. ActionController::Dispatcher.middleware.delete ActionDispatch::ShowExceptions ActionController::Dispatcher.middleware.delete ActionDispatch::Rescue ActionController::Dispatcher.middleware.use 'Rack::Hoptoad', 'my-api-key' ActionController::Dispatcher.middleware.use 'Rack::ShowExceptions' Saturday, July 25, 2009
  73. 73. 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 Saturday, July 25, 2009
  74. 74. module Rack class Hoptoad def notify_hoptoad(exception, env) headers = { 'Content-type' => 'application/x-yaml', 'Accept' => 'text/xml, application/xml' } url = URI.parse("http://hoptoadapp.com/notices") http = Net::HTTP.new(url.host, url.port) data = { :api_key => @api_key, :error_message => "#{exception.class}: #{exception}", :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 Saturday, July 25, 2009
  75. 75. Saturday, July 25, 2009
  76. 76. Intangibles Saturday, July 25, 2009
  77. 77. Saturday, July 25, 2009
  78. 78. Saturday, July 25, 2009
  79. 79. Saturday, July 25, 2009
  80. 80. Saturday, July 25, 2009
  81. 81. Saturday, July 25, 2009
  82. 82. Thank You ben scofield - @bscofield - http://www.viget.com/extend - http://www.speakerrate.com/bscofield Saturday, July 25, 2009

×