The Lifecycle of a Rails Response

The Lifecycle of a Rails Response

This breathtaking documentary series combines rare action, unimaginable scale, impossible locations and intimate moments captured from the deepest depths of Rails internals. Last year, we followed the lifecycle of best loved, wildest and most elusive Rails components through a request, from the browser to a controller action. This year, our journey takes us across the great text/plain, following the flow of HTTP streams, taking in the spectacular Action View as we find our way back to the browser. Join us to unearth the amazing lifecycle of a Rails response.

137928070f64f02ea3da2cddaf0e8d65?s=128

Krystan HuffMenne

May 04, 2020
Tweet

Transcript

  1. INSIDE RAILS The Lifecycle of a Response

  2. None
  3. None
  4. https://skylight.io/r/railsconf Don’t struggle to learn why your app is slow.

    Get answers with Skylight. DO THE ANSWER DANCE. SKYLIGHT
  5. None
  6. None
  7. None
  8. app/controllers/hello_controller.rb Terminal $ Trying 34.194.84.73... Connected to ec2-34-194-84-73.compute-1.amazonaws.com. Escape character

    is ‘^]’. > telnet 34.194.84.73 80 Picture: Masai Mara Wildlife / Matt Scobel / CC BY 3.0
  9. app/controllers/hello_controller.rb class SafariController < ActionController::Base def hello # ...do stuff

    here... render plain: 'Hello World' end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb Terminal $ Trying 34.194.84.73... Connected to ec2-34-194-84-73.compute-1.amazonaws.com. Escape character is ‘^]’. > telnet 34.194.84.73 80 GET /safari HTTP/1.1 > Host: skylight.io > Picture: Masai Mara Wildlife / Matt Scobel / CC BY 3.0
  10. app/controllers/hello_controller.rb Terminal $ Trying 34.194.84.73... Connected to ec2-34-194-84-73.compute-1.amazonaws.com. Escape character

    is ‘^]’. > telnet 34.194.84.73 80 GET /safari HTTP/1.1 > Host: skylight.io > < HTTP/1.1 200 OK < Content-Type: text/plain < Content-Length: 11 < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Hello World app/controllers/hello_controller.rb class SafariController < ActionController::Base def hello # ...do stuff here... render plain: 'Hello World' end end app/controllers/safari_controller.rb Picture: Three Elephants in Early Morning / Yu Miyawaki / CC BY 3.0
  11. HELLO WORLD! http://skylight.io/safari

  12. app/controllers/hello_controller.rb http://skylight.io/safari Roar Savanna

  13. Ok…..? Hey, I have a request for you to handle.

  14. Sounds good. It’s a GET request for /safari, Host header

    is skylight.io 200 OK. Content type is text/plain, body is “Roar Savanna”. Hey, I have a request for you to handle.
  15. app/controllers/hello_controller.rb http://skylight.io/safari app/controllers/hello_controller.rb Terminal $ Trying 34.194.84.73... Connected to ec2-34-194-84-73.compute-1.amazonaws.com.

    Escape character is ‘^]’. > telnet 34.194.84.73 80
  16. app/controllers/hello_controller.rb http://skylight.io/safari app/controllers/hello_controller.rb Terminal $ Trying 34.194.84.73... Connected to ec2-34-194-84-73.compute-1.amazonaws.com.

    Escape character is ‘^]’. > telnet 34.194.84.73 80 GET /safari HTTP/1.1 > Host: skylight.io >
  17. app/controllers/hello_controller.rb http://skylight.io/safari app/controllers/hello_controller.rb Terminal $ Trying 34.194.84.73... Connected to ec2-34-194-84-73.compute-1.amazonaws.com.

    Escape character is ‘^]’. > telnet 34.194.84.73 80 < HTTP/1.1 200 OK < Content-Type: text/plain < Content-Length: 12 < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Roar Savanna GET /safari HTTP/1.1 > Host: skylight.io > Roar Savanna
  18. handwave handwave Check out last year's talk for more info!

  19. RACK

  20. None
  21. app/controllers/hello_controller.rb http://skylight.io/safari app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO'

    => ‘/safari', 'HTTP_HOST' => 'skylight.io', # ... } server.rb
  22. app/controllers/hello_controller.rb http://skylight.io/safari app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO'

    => ‘/safari', 'HTTP_HOST' => 'skylight.io', # ... } app.call(env) server.rb
  23. app/controllers/hello_controller.rb http://skylight.io/safari app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO'

    => ‘/safari', 'HTTP_HOST' => 'skylight.io', # ... } app.call(env) server.rb handwave handwave Check out last year's talk for more info!
  24. app/controllers/hello_controller.rb http://skylight.io/safari app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO'

    => ‘/safari', 'HTTP_HOST' => 'skylight.io', # ... } app.call(env) server.rb app/controllers/hello_controller.rb class SafariController < ActionController::Base def hello # Get it? A savanna is a type of plain... render plain: 'Roar Savanna' end end app/controllers/safari_controller.rb
  25. app/controllers/hello_controller.rb http://skylight.io/safari app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO'

    => ‘/safari', 'HTTP_HOST' => 'skylight.io', # ... } status, headers, body = app.call(env) status # => 200 headers # => { 'Content-Type' => 'text/plain' } body # => [‘Roar Savanna’] server.rb 1 2 3 The Response Array
  26. app/controllers/hello_controller.rb http://skylight.io/safari Roar Savanna app/controllers/hello_controller.rb < HTTP/1.1 200 OK <

    Content-Type: text/plain < Content-Length: 12 < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Roar Savanna
  27. app/controllers/hello_controller.rb http://skylight.io/safari Roar Savanna app/controllers/hello_controller.rb < HTTP/1.1 200 OK <

    Content-Type: text/plain < Content-Length: 12 < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Roar Savanna
  28. None
  29. app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => ‘/safari',

    'HTTP_HOST' => 'skylight.io', # ... } status, headers, body = app.call(env) status # => 200 headers # => { 'Content-Type' => 'text/plain' } body # => [‘Roar Savanna’] server.rb 1 The Response Array
  30. 1xx — 2xx — 3xx — 4xx — 5xx —

    STATUS CODES Informational Success!! Redirection Client Error Server Error
  31. Here’s a GET request for /safari, Host header is skylight.io

    OMG I DID IT! Roar Savanna! Huh?
  32. Great, I can render that. Here’s a GET request for

    /safari, Host header is skylight.io 200 OK; Roar Savanna
  33. Should I index the page at /safari ? 500 Internal

    Server Error OK, I’ll be back later! … How about now? 200 OK; Roar Savanna Great! I’ve indexed it.
  34. 1xx — 2xx — 3xx — 4xx — 5xx —

    STATUS CODES Informational Success!! Redirection Client Error Server Error PRO-TIP! Learn a lot more about status codes by going to httpstatuses.com
  35. app/controllers/hello_controller.rb class SafariController < ApplicationController def eat_hippo consume_hippo if @current_user.lion?

    head :no_content # 204 end end app/controllers/safari_controller.rb
  36. app/controllers/hello_controller.rb class SafariController < ApplicationController def eat_hippo consume_hippo if @current_user.lion?

    head :no_content # 204 end end app/controllers/safari_controller.rb
  37. app/controllers/hello_controller.rb class SafariController < ApplicationController def eat_hippo consume_hippo if @current_user.lion?

    head :no_content # 204 end end app/controllers/safari_controller.rb
  38. app/controllers/hello_controller.rb class SafariController < ApplicationController def eat_hippo consume_hippo if @current_user.lion?

    head :no_content # 204 end end app/controllers/safari_controller.rb
  39. app/controllers/hello_controller.rb class SafariController < ApplicationController def eat_hippo consume_hippo if @current_user.lion?

    head :no_content # 204 end end app/controllers/safari_controller.rb
  40. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } before_action { redirect_to oasis_url if dry_season? } def find_hippo render :hippo end end app/controllers/safari_controller.rb
  41. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } before_action { redirect_to oasis_url if dry_season? } def find_hippo render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 302 Found < Location: https://www.skylight.io/oasis < Content-Type: text/plain < Date: Thu, 25 Apr 2019 18:52:54 GMT
  42. None
  43. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo redirect_to oasis_url, status: :moved_permanently end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 301 Moved Permanently < Location: https://www.skylight.io/oasis < Content-Type: text/plain < Date: Thu, 25 Apr 2019 18:52:54 GMT
  44. app/controllers/hello_controller.rb Rails.application.routes.draw do get '/find-hippo', to: redirect('/oasis') end config/routes.rb app/controllers/hello_controller.rb

    < HTTP/1.1 301 Moved Permanently < Location: https://www.skylight.io/oasis < Content-Type: text/plain < Date: Thu, 25 Apr 2019 18:52:54 GMT
  45. DANGER!

  46. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo redirect_to oasis_url if dry_season? render :hippo end end app/controllers/safari_controller.rb
  47. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo redirect_to oasis_url if dry_season? render :hippo end end app/controllers/safari_controller.rb http://skylight.io/find-hippo
  48. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } before_action { redirect_to oasis_url if dry_season? } def find_hippo render :hippo end end app/controllers/safari_controller.rb
  49. Here’s a GET request for /safari, Host header is skylight.io

    200 OK; Roar Savanna Great, I can render that. Wait…I need more information.
  50. Here’s a GET request for /safari, Host header is skylight.io

    200 OK; Roar Savanna Great, I can render that. Wait…I need more information. Oh yeah. It’s a plain text response. Oh! OK!
  51. app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => ‘/safari',

    'HTTP_HOST' => 'skylight.io', # ... } status, headers, body = app.call(env) status # => 200 headers # => { 'Content-Type' => 'text/plain' } body # => [‘Roar Savanna’] server.rb 1 2 The Response Array
  52. app/controllers/hello_controller.rb < HTTP/1.1 302 Found < Content-Type: text/plain < Location:

    https://www.skylight.io/oasis < Date: Thu, 25 Apr 2019 18:52:54 GMT
  53. app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/plain < Content-Length:

    12 < Set-Cookie: _safari_session=some-token; < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Roar Savanna
  54. app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/plain < Content-Length:

    12 < Set-Cookie: _safari_session=some-token; < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Roar Savanna
  55. app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/plain < Content-Length:

    12 < Set-Cookie: _safari_session=some-token; < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Roar Savanna
  56. app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/plain < Content-Length:

    12 < Set-Cookie: _safari_session=some-token; < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Roar Savanna
  57. app/controllers/hello_controller.rb response.headers['HEADER NAME'] = 'header value'

  58. Here’s a GET request for /safari, Host header is skylight.io

    … 200 OK; Roar Savanna Thanks!
  59. Here’s a GET request for /safari, Host header is skylight.io

    200 OK; Roar Savanna Here’s a GET request for /safari, Host header is skylight.io Just use the last 200 Nice! Thanks!
  60. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb PRO-TIP! Turn on caching in development by running rails dev:cache
  61. HIPPOS ARE BIG

  62. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo http_cache_forever { render :hippo } end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=3155695200, private < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  63. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo http_cache_forever { render :hippo } end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=3155695200, private < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  64. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo http_cache_forever(public: true) { render :hippo } end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=3155695200, public < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  65. app/controllers/hello_controller.rb <%= image_tag "hippo.png" %> app/views/safari/hippo.html.erb

  66. app/controllers/hello_controller.rb <%= image_tag "hippo.png" %> app/views/safari/hippo.html.erb app/controllers/hello_controller.rb http://skylight.io/find-hippo <img src=“/assets/hippo-f90d8a84c707a8dc923fca1

    ca1895ae8ed0a09237f6992015fef1e11be77c023.png">
  67. app/controllers/hello_controller.rb <%= image_tag "hippo.png" %> app/views/safari/hippo.html.erb app/controllers/hello_controller.rb http://skylight.io/find-hippo <img src=“/assets/hippo-f90d8a84c707a8dc923fca1

    ca1895ae8ed0a09237f6992015fef1e11be77c023.png">
  68. app/controllers/hello_controller.rb <%= image_tag "hippo.png" %> app/views/safari/hippo.html.erb app/controllers/hello_controller.rb http://skylight.io/find-hippo <img src=“/assets/hippo-f90d8a84c707a8dc923fca1

    ca1895ae8ed0a09237f6992015fef1e11be77c023.png">
  69. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo http_cache_forever { render :hippo } end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=3155695200, private < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  70. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo expires_in 1.hour render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=3600, private < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  71. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo expires_in 1.hour render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=3600, private < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  72. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb
  73. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=0, private, must-revalidate < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  74. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=0, private, must-revalidate < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  75. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb <!DOCTYPE html> <html> <head> <title>Safari</title> <link rel="stylesheet" media=“all" href="/assets/application-gobbledygook.css" /> <script src="/packs/js/application-gobbledygook.js"></script> </head> <body>
  76. app/controllers/hello_controller.rb # a simplified Rack::ETag module Rack class ETag def

    initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if status == 200 digest = digest_body(body) headers[Etag] = %(W/"#{digest}") end [status, headers, body] end private #... end end rack/lib/rack/etag.rb
  77. app/controllers/hello_controller.rb # a simplified Rack::ETag module Rack class ETag def

    initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if status == 200 digest = digest_body(body) headers[Etag] = %(W/"#{digest}") end [status, headers, body] end private #... end end rack/lib/rack/etag.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=0, private, must-revalidate < ETag: W/“48a7e47309e0ec54e32df3a272094025" < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  78. app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control:

    max-age=0, private, must-revalidate < ETag: W/“48a7e47309e0ec54e32df3a272094025" < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html> app/controllers/hello_controller.rb > GET /find-hippo HTTP/1.1 > Host: skylight.io > If-None-Match: W/"48a7e47309e0ec54e32df3a272094025"
  79. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb <!DOCTYPE html> <html> <head> <title>Safari</title> <link rel="stylesheet" media=“all" href="/assets/application-gobbledygook.css" /> <script src="/packs/js/application-gobbledygook.js"></script> </head> <body>
  80. app/controllers/hello_controller.rb # a simplified Rack::ETag module Rack class ETag def

    initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if status == 200 digest = digest_body(body) headers[Etag] = %(W/"#{digest}") end [status, headers, body] end private #... end end rack/lib/rack/etag.rb
  81. app/controllers/hello_controller.rb # a simplified Rack::ETag module Rack class ETag def

    initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if status == 200 digest = digest_body(body) headers[Etag] = %(W/"#{digest}") end [status, headers, body] end private #... end end rack/lib/rack/etag.rb
  82. app/controllers/hello_controller.rb # a simplified Rack::ETag module Rack class ETag def

    initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if status == 200 digest = digest_body(body) headers[Etag] = %(W/"#{digest}") end [status, headers, body] end private #... end end rack/lib/rack/etag.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=0, private, must-revalidate < ETag: W/“48a7e47309e0ec54e32df3a272094025" < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  83. app/controllers/hello_controller.rb # a simplified Rack::ConditionalGet module Rack class ConditionalGet def

    initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if status == 200 && etag_matches? status = 304 body = [] end [status, headers, body] end private def etag_matches? headers['ETag'] == env['HTTP_IF_NONE_MATCH'] end end end rack/lib/rack/conditional_get.rb
  84. app/controllers/hello_controller.rb # a simplified Rack::ConditionalGet module Rack class ConditionalGet def

    initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if status == 200 && etag_matches? status = 304 body = [] end [status, headers, body] end private def etag_matches? headers['ETag'] == env['HTTP_IF_NONE_MATCH'] end end end rack/lib/rack/conditional_get.rb app/controllers/hello_controller.rb < HTTP/1.1 304 Not Modified < Cache-Control: max-age=0, private, must-revalidate < ETag: W/“48a7e47309e0ec54e32df3a272094025” < Content-Type: text/html < Date: Thu, 25 Apr 2019 18:52:54 GMT <
  85. app/controllers/hello_controller.rb # a simplified Rack::ConditionalGet module Rack class ConditionalGet def

    initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if status == 200 && etag_matches? status = 304 body = [] end [status, headers, body] end private def etag_matches? headers['ETag'] == env['HTTP_IF_NONE_MATCH'] end end end rack/lib/rack/conditional_get.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Cache-Control: max-age=0, private, must-revalidate < ETag: W/“48a7e47309e0ec54e32df3a272094025” < Content-Type: text/html < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  86. None
  87. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo if stale?(@hippo) end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=0, private, must-revalidate < ETag: W/“48a7e47309e0ec54e32df3a272094025" < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html> app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=0, private, must-revalidate < ETag: W/"60bee75b8031cda7761a332685151766" < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  88. app/controllers/hello_controller.rb <!DOCTYPE html> <html> <head> <title>Safari</title> <link rel="stylesheet" media=“all" href="/assets/application-gobbledygook.css"

    /> <script src="/packs/js/application-gobbledygook.js"></script> </head> <body> </body> </html>
  89. app/controllers/hello_controller.rb "hippo/1-20071224150000"

  90. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo if stale?(@hippo) end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: max-age=0, private, must-revalidate < ETag: W/"60bee75b8031cda7761a332685151766" < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  91. None
  92. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo response.headers["Cache-Control"] = "no-store" render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: no-store < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  93. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo response.headers["Cache-Control"] = "no-store" render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Cache-Control: no-store < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html> no-store ≠ no-cache
  94. THE RESPONSE BODY and finally…

  95. app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => ‘/safari',

    'HTTP_HOST' => 'skylight.io', # ... } status, headers, body = app.call(env) status # => 200 headers # => { 'Content-Type' => 'text/plain' } body # => [‘Roar Savanna’] server.rb 1 2 3 The Response Array
  96. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb <!DOCTYPE html> <html> <head> <title>Safari</title> <link rel="stylesheet" media=“all" href="/assets/application-gobbledygook.css" /> <script src="/packs/js/application-gobbledygook.js"></script> </head> <body>
  97. app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Date:

    Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  98. http://skylight.io/safari.html

  99. app/controllers/hello_controller.rb > GET /find-hippo HTTP/1.1 > Host: skylight.io > Accept:

    text/html,application/xhtml+xml,application/xml;
  100. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb
  101. http://skylight.io/find-hippo.json

  102. http://skylight.io/find-hippo.json

  103. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo respond_to do |format| format.html { render :hippo } format.json { render json: @hippo } end end end app/controllers/safari_controller.rb
  104. http://skylight.io/find-hippo { "id": 1, "name": "Jason", "created_at": "2020-04-10T17:14:20.771Z", "updated_at": "2020-04-10T17:14:20.771Z"

    } app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Cache-Control: max-age=0, private, must-revalidate < Date: Thu, 25 Apr 2019 18:52:54 GMT < Content-Type: application/json < < {"id": 1, "name": “Jason", … }
  105. app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < X-Content-Type-Options:

    nosniff < Cache-Control: max-age=0, private, must-revalidate < Date: Thu, 25 Apr 2019 18:52:54 GMT < < <html>…</html>
  106. TEMPLATE RENDERING

  107. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb
  108. app/controllers/hello_controller.rb class SafariController < ApplicationController before_action { @hippo = Hippo.first

    } def find_hippo render :hippo end end app/controllers/safari_controller.rb app/controllers/hello_controller.rb Hey <%= current_user.name %>, meet <%= link_to @hippo.name, @hippo %>! app/views/safari/hippo.html.erb
  109. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end NOTE: To see the actual code, look in ActionView!::Rendering, ActionView!::Base, ActionView!::Renderer, ActionView!::TemplateRenderer, ActionView!::Template
  110. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  111. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  112. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  113. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  114. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  115. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  116. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  117. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  118. app/controllers/hello_controller.rb class SafariControllerViewContext < ActionView::Base include Rails::AllTheHelpers # link_to, etc.

    include MyApp::AllTheHelpers # current_user, etc. def initialize(assigns) assigns.each { |k, v| instance_variable_set("@#{k}", v) } end private # Hey <%= current_user.name %>, meet # <%= link_to @hippo.name, @hippo %>! def __compiled_app_templates_hippo_erb output = "" output << "Hey " output << html_escape(current_user.name) output << ", meet" output << link_to(html_escape(@hippo.name), @hippo) output << "!" output end end
  119. http://skylight.io/find-hippo <!DOCTYPE html> <html> <head> <title>Safari</title> <link rel="stylesheet" media="all" href="/assets/application-gobbledygook.css"

    /> <script src="/packs/js/application-gobbledygook.js"></script> </head> <body> Hey RailsConf, meet <a href="/hippos/1">Phyllis</a>! </body> </html> Hey RailsConf, meet Phyllis!
  120. http://skylight.io/find-hippo <!DOCTYPE html> <html> <head> <title>Safari</title> <link rel="stylesheet" media="all" href="/assets/application-gobbledygook.css"

    /> <script src="/packs/js/application-gobbledygook.js"></script> </head> <body> Hey RailsConf, meet <a href="/hippos/1">Phyllis</a>! </body> </html> Hey RailsConf, meet Phyllis! app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Content-Length: 306 < Cache-Control: max-age=0, private, must-revalidate < ETag: W/“60bee75b8031cda7761a332685151766” < Set-Cookie: _safari_session=some-session-token; path=/; < X-Content-Type-Options: nosniff < Date: Thu, 25 Apr 2019 18:52:54 GMT
  121. None