Slide 1

Slide 1 text

INSIDE RAILS The Lifecycle of a Response

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

https://skylight.io/r/railsconf Don’t struggle to learn why your app is slow. Get answers with Skylight. DO THE ANSWER DANCE. SKYLIGHT

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

HELLO WORLD! http://skylight.io/safari

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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.

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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 >

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

handwave handwave Check out last year's talk for more info!

Slide 19

Slide 19 text

RACK

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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!

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

1xx — 2xx — 3xx — 4xx — 5xx — STATUS CODES Informational Success!! Redirection Client Error Server Error

Slide 31

Slide 31 text

Here’s a GET request for /safari, Host header is skylight.io OMG I DID IT! Roar Savanna! Huh?

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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.

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

DANGER!

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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.

Slide 50

Slide 50 text

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!

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

app/controllers/hello_controller.rb response.headers['HEADER NAME'] = 'header value'

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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!

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

HIPPOS ARE BIG

Slide 62

Slide 62 text

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 < < …

Slide 63

Slide 63 text

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 < < …

Slide 64

Slide 64 text

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 < < …

Slide 65

Slide 65 text

app/controllers/hello_controller.rb <%= image_tag "hippo.png" %> app/views/safari/hippo.html.erb

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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 < < …

Slide 70

Slide 70 text

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 < < …

Slide 71

Slide 71 text

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 < < …

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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 < < …

Slide 74

Slide 74 text

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 < < …

Slide 75

Slide 75 text

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 Safari

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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 < < …

Slide 78

Slide 78 text

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 < < … app/controllers/hello_controller.rb > GET /find-hippo HTTP/1.1 > Host: skylight.io > If-None-Match: W/"48a7e47309e0ec54e32df3a272094025"

Slide 79

Slide 79 text

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 Safari

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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 < < …

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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 <

Slide 85

Slide 85 text

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 < < …

Slide 86

Slide 86 text

No content

Slide 87

Slide 87 text

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 < < … 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 < < …

Slide 88

Slide 88 text

app/controllers/hello_controller.rb Safari

Slide 89

Slide 89 text

app/controllers/hello_controller.rb "hippo/1-20071224150000"

Slide 90

Slide 90 text

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 < < …

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

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 < < …

Slide 93

Slide 93 text

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 < < … no-store ≠ no-cache

Slide 94

Slide 94 text

THE RESPONSE BODY and finally…

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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 Safari

Slide 97

Slide 97 text

app/controllers/hello_controller.rb < HTTP/1.1 200 OK < Content-Type: text/html < Date: Thu, 25 Apr 2019 18:52:54 GMT < < …

Slide 98

Slide 98 text

http://skylight.io/safari.html

Slide 99

Slide 99 text

app/controllers/hello_controller.rb > GET /find-hippo HTTP/1.1 > Host: skylight.io > Accept: text/html,application/xhtml+xml,application/xml;

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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", … }

Slide 105

Slide 105 text

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 < < …

Slide 106

Slide 106 text

TEMPLATE RENDERING

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

http://skylight.io/find-hippo Safari Hey RailsConf, meet Phyllis! Hey RailsConf, meet Phyllis!

Slide 120

Slide 120 text

http://skylight.io/find-hippo Safari Hey RailsConf, meet Phyllis! 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

Slide 121

Slide 121 text

No content