Slide 1

Slide 1 text

app/controllers/hello_controller.rb Hello World http://skylight.io/hello app/controllers/hello_controller.rb class HelloController < ActionController::Base def index # ...do stuff here... render plain: 'Hello World' end end app/controllers/hello_controller.rb

Slide 2

Slide 2 text

Meet at Pastini? where dat 911 SW Taylor St, Portland, OR 97205

Slide 3

Slide 3 text

app/controllers/hello_controller.rb What’s the address for skylight.io? 34.194.84.73 http://skylight.io/hello

Slide 4

Slide 4 text

app/controllers/hello_controller.rb http://skylight.io/hello DNS LOOKUP Domain Name System

Slide 5

Slide 5 text

app/controllers/hello_controller.rb http://skylight.io/hello app/controllers/hello_controller.rb $ dig skylight.io
 
 ; <<>> DiG 9.10.6 <<>> skylight.io ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32689 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;skylight.io. IN A ;; ANSWER SECTION: skylight.io. 59 IN A 34.194.84.73 ;; Query time: 34 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Mon Apr 29 14:50:34 PDT 2019 ;; MSG SIZE rcvd: 56 Terminal

Slide 6

Slide 6 text

app/controllers/hello_controller.rb http://skylight.io/hello app/controllers/hello_controller.rb $ dig skylight.io
 
 ; <<>> DiG 9.10.6 <<>> skylight.io ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32689 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;skylight.io. IN A ;; ANSWER SECTION: skylight.io. 59 IN A 34.194.84.73 ;; Query time: 34 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Mon Apr 29 14:50:34 PDT 2019 ;; MSG SIZE rcvd: 56 Terminal

Slide 7

Slide 7 text

app/controllers/hello_controller.rb http://skylight.io/hello 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
 
 
 < Connection closed by foreign host. 
 Hi???

Slide 8

Slide 8 text

app/controllers/hello_controller.rb http://skylight.io/hello 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: 11 < Date: Thu, 25 Apr 2019 18:52:54 GMT < < Hello World 
 GET /hello HTTP/1.1 > Host: skylight.io > Hello World

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

hey server, can you do me a favor? What’s up? If someone ask for /assets/*, can you give it to them from /var/myapp/public/assets? Sure thing. With compression, 404, etc. The usual.

Slide 11

Slide 11 text

app/controllers/hello_controller.rb http://skylight.io/assets/kitten.jpg app/controllers/hello_controller.rb location /assets { alias /var/myapp/public/assets; gzip_static on; gzip on; expires max; add_header Cache-Control public; } nginx.conf © Kenny Louie, CC BY 2.0

Slide 12

Slide 12 text

app/controllers/hello_controller.rb http://skylight.io/blog ! location /blog { } nginx.conf !

Slide 13

Slide 13 text

app/controllers/hello_controller.rb server.on_request do |request, response| request.path # => '/hello' request.headers # => { host: ... } response.status = 200 response.body = 'Hello World' end app/controllers/hello_controller.rb MyApp.handle_request( http_method, # => 'GET' http_path, # => '/hello' http_headers # => # ) # => # app/controllers/hello_controller.rb ENV['REQUEST_METHOD'] # => 'GET' ENV['PATH_INFO'] # => '/hello' ENV['HTTP_HOST'] # => 'skylight.io' puts 'Status: 200 OK' puts puts 'Hello World'

Slide 14

Slide 14 text

Hey, I’ve a request for you to handle. Sounds good. It’s a GET request for /hello, Host header is skylight.io 200 OK. Content type is text/plain, body is “Hello World”.

Slide 15

Slide 15 text

app/controllers/hello_controller.rb Hello World http://skylight.io/hello app/controllers/hello_controller.rb env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/hello', 'HTTP_HOST' => 'skylight.io', # ... } status, headers, body = app.call(env) status # => 200 headers # => { 'Content-Type' => 'text/plain' } body # => ['Hello World'] server.rb

Slide 16

Slide 16 text

app/controllers/hello_controller.rb Terminal $ app/controllers/hello_controller.rb class HelloWorld def call(env) if env['PATH_INFO'] == '/hello' [200, {'Content-Type' => 'text/plain'}, ['Hello World']] else [404, {'Content-Type' => 'text/plain'}, ['Not Found']] end end end app.rb app/controllers/hello_controller.rb require_relative 'app' run HelloWorld.new config.ru rackup Thin web server (v1.7.2 codename Bachmanity) Maximum connections set to 1024 Listening on localhost:9292, CTRL+C to stop app/controllers/hello_controller.rb Hello World http://localhost:9292/hello app/controllers/hello_controller.rb Not Found http://localhost:9292/wat

Slide 17

Slide 17 text

app/controllers/hello_controller.rb class HelloWorld def call(env) if env['PATH_INFO'] == '/' [301, {'Location' => '/hello'}, []] elsif env['PATH_INFO'] == '/hello' [200, {'Content-Type' => 'text/plain'}, ['Hello World!']] else [404, {'Content-Type' => 'text/plain'}, ['Not Found!']] end end end app.rb

Slide 18

Slide 18 text

app/controllers/hello_controller.rb class Redirect def initialize(app, from:, to:) @app = app @from = from @to = to end def call(env) if env["PATH_INFO"] == @from [301, {"Location" => @to}, []] else @app.call(env) end end end class HelloWorld def call(env) if env["PATH_INFO"] == '/hello' [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] else [404, {"Content-Type" => "text/plain"}, ["Not Found!"]] end end end app.rb app/controllers/hello_controller.rb require_relative 'app' run Redirect.new( HelloWorld.new, from: '/', to: '/hello' ) config.ru

Slide 19

Slide 19 text

app/controllers/hello_controller.rb class Redirect def initialize(app, from:, to:) @app = app @from = from @to = to end def call(env) if env["PATH_INFO"] == @from [301, {"Location" => @to}, []] else @app.call(env) end end end class HelloWorld def call(env) if env["PATH_INFO"] == '/hello' [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] else [404, {"Content-Type" => "text/plain"}, ["Not Found!"]] end end end app.rb app/controllers/hello_controller.rb require_relative 'app' use Redirect, from: '/', to: '/hello' run HelloWorld.new config.ru

Slide 20

Slide 20 text

app/controllers/hello_controller.rb class Redirect def initialize(app, from:, to:) @app = app @from = from @to = to end def call(env) if env["PATH_INFO"] == @from [301, {"Location" => @to}, []] else @app.call(env) end end end class HelloWorld def call(env) if env["PATH_INFO"] == '/hello' [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] else [404, {"Content-Type" => "text/plain"}, ["Not Found!"]] end end end app.rb app/controllers/hello_controller.rb require_relative 'app' use Rack::Deflater use Rack::Head use Rack::ConditionalGet use Rack::ETag use Redirect, from: '/', to: '/hello' run HelloWorld.new config.ru

Slide 21

Slide 21 text

app/controllers/hello_controller.rb require_relative 'config/environment' run Rails.application config.ru app/controllers/hello_controller.rb $ Terminal bin/rails console >> Rails.application.call({ ...env hash... })

Slide 22

Slide 22 text

app/controllers/hello_controller.rb require_relative 'config/environment' run Rails.application config.ru app/controllers/hello_controller.rb $ Terminal bin/rails console >> env = { >> 'REQUEST_METHOD' => 'GET', >> 'PATH_INFO' => ‘/posts/1’, >> 'HTTP_HOST' => 'localhost', >> 'HTTP_PORT' => '3000', >> # ... >> } >> Rails.application.call(env)

Slide 23

Slide 23 text

app/controllers/hello_controller.rb require_relative 'config/environment' run Rails.application config.ru app/controllers/hello_controller.rb $ bin/rails console >> env = Rack::MockRequest.env_for('http://localhost:3000/posts/1') >> Terminal

Slide 24

Slide 24 text

app/controllers/hello_controller.rb require_relative 'config/environment' run Rails.application config.ru app/controllers/hello_controller.rb $ bin/rails console >> env = Rack::MockRequest.env_for('http://localhost:3000/posts/1') >> Terminal status, headers, body = Rails.application.call(env) Processing by PostsController#show as HTML Parameters: {"id"=>"1"} CACHE Post Load (0.0ms) SELECT "posts".* FROM "posts" WHERE ... Rendering posts/show.html.erb within layouts/application Rendered posts/show.html.erb within layouts/application (0.3ms) Completed 200 OK in 23ms (Views: 21.1ms | ActiveRecord: 0.0ms) >> status => 200 >> headers => { "Content-Type"=>"text/html; charset=utf-8”, ... } >> puts body.join('') My Blorgh

Rails is Omakase

There are lots of à la carte software environments in...

Slide 25

Slide 25 text

app/controllers/hello_controller.rb $ Terminal bin/rails middleware use Rack::Sendfile use ActionDispatch::Executor use ActiveSupport::Cache::Strategy::LocalCache::Middleware use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use ActionDispatch::RemoteIp use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use ActionDispatch::Callbacks use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ContentSecurityPolicy::Middleware use Rack::Head use Rack::ConditionalGet use Rack::ETag use Rack::TempfileReaper run Blorgh::Application.routes

Slide 26

Slide 26 text

app/controllers/hello_controller.rb require_relative 'boot' require 'rails/all' Bundler.require(*Rails.groups) module Blorgh class Application < Rails::Application # Disable cookies config.middleware.delete ActionDispatch::Cookies config.middleware.delete ActionDispatch::Session::CookieStore config.middleware.delete ActionDispatch::Flash # Add your own middleware config.middleware.use CaptchaEverywhere end end config/application.rb

Slide 27

Slide 27 text

app/controllers/hello_controller.rb $ Terminal bin/rails middleware use Rack::Sendfile use ActionDispatch::Executor use ActiveSupport::Cache::Strategy::LocalCache::Middleware use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use ActionDispatch::RemoteIp use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use ActionDispatch::Callbacks use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ContentSecurityPolicy::Middleware use Rack::Head use Rack::ConditionalGet use Rack::ETag use Rack::TempfileReaper run Blorgh::Application.routes

Slide 28

Slide 28 text

app/controllers/hello_controller.rb $ bin/rails >> env = Rack::MockRequest.env_for('http://localhost:3000/posts/1') >> Terminal console status, headers, body = Blorgh::Application.routes.call(env) Processing by PostsController#show as HTML Parameters: {"id"=>"1"} CACHE Post Load (0.0ms) SELECT "posts".* FROM "posts" WHERE ... Rendering posts/show.html.erb within layouts/application Rendered posts/show.html.erb within layouts/application (0.3ms) Completed 200 OK in 23ms (Views: 21.1ms | ActiveRecord: 0.0ms) >> status => 200 >> headers => { "Content-Type"=>"text/html; charset=utf-8”, ... } >> puts body.join('') My Blorgh

Rails is Omakase

There are lots of à la carte software environments in...

Slide 29

Slide 29 text

app/controllers/hello_controller.rb Rails.application.routes.draw do resources :posts end config/routes.rb

Slide 30

Slide 30 text

app/controllers/hello_controller.rb Rails.application.routes.draw do get '/posts' => 'posts#index' get '/posts/new' => 'posts#new' post '/posts' => 'posts#create' get '/posts/:id' => 'posts#show' get '/posts/:id/edit' => 'posts#edit' put '/posts/:id' => 'posts#update' delete '/posts/:id' => 'posts#destroy' end config/routes.rb

Slide 31

Slide 31 text

app/controllers/hello_controller.rb Rails.application.routes.draw do get '/posts' => 'posts#index' get '/posts/new' => 'posts#new' post '/posts' => 'posts#create' get '/posts/:id' => 'posts#show' get '/posts/:id/edit' => 'posts#edit' put '/posts/:id' => 'posts#update' delete '/posts/:id' => 'posts#destroy' end config/routes.rb PostsController.action(:index)

Slide 32

Slide 32 text

app/controllers/hello_controller.rb class ActionController::Base def self.action(name) ->(env) { request = ActionDispatch::Request.new(env) response = ActionDispatch::Response.new(request) controller = self.new(request, response) controller.process_action(name) response.to_a } end attr_reader :request, :response, :params def initialize(request, response) @request = request @response = response @params = request.params end def process_action(name) event = 'process_action.action_controller' payload = { controller: self.class.name, action: action_name, # ... } ActiveSupport::Notifications.instrument(event, payload) do self.send(name) end end end rails/actionpack/lib/action_controller/base.rb

Slide 33

Slide 33 text

app/controllers/hello_controller.rb class ActionController::Base def self.action(name) ->(env) { request = ActionDispatch::Request.new(env) response = ActionDispatch::Response.new(request) controller = self.new(request, response) controller.process_action(name) response.to_a } end attr_reader :request, :response, :params def initialize(request, response) @request = request @response = response @params = request.params end def process_action(name) event = 'process_action.action_controller' payload = { controller: self.class.name, action: action_name, # ... } ActiveSupport::Notifications.instrument(event, payload) do self.send(name) end end end rails/actionpack/lib/action_controller/base.rb

Slide 34

Slide 34 text

app/controllers/hello_controller.rb class BlorghRoutes def call(env) verb = env['REQUEST_METHOD'] path = env['PATH_INFO'] if verb == 'GET' && path == '/posts' PostsController.action(:index).call(env) elsif verb == 'GET' && path == '/posts/new' PostsController.action(:new).call(env) elsif verb == ‘POST' && path == '/posts' PostsController.action(:create).call(env) elsif verb == 'GET' && path =~ %r(/posts/.+) PostsController.action(:show).call(env) elsif verb == 'GET' && path =~ %r(/posts/.+/edit) PostsController.action(:edit).call(env) elsif verb == 'PUT' && path =~ %r(/posts) PostsController.action(:update).call(env) elsif verb == 'DELETE' && path = %r(/posts/.+) PostsController.action(:destroy).call(env) else [404, {'Content-Type': 'text-plain', ...}, ['Not Found!']] end end end blorgh_routes.rb

Slide 35

Slide 35 text

app/controllers/hello_controller.rb class BlorghRoutes def call(env) verb = env['REQUEST_METHOD'] path = env['PATH_INFO'] if verb == 'GET' && path == '/posts' PostsController.action(:index).call(env) elsif verb == 'GET' && path == '/posts/new' PostsController.action(:new).call(env) elsif verb == 'GET' && path == '/posts' PostsController.action(:create).call(env) elsif verb == 'GET' && path =~ %r(/posts/.+) PostsController.action(:show).call(env) elsif verb == 'GET' && path =~ %r(/posts/.+/edit) PostsController.action(:edit).call(env) elsif verb == 'PUT' && path =~ %r(/posts) PostsController.action(:update).call(env) elsif verb == 'DELETE' && path = %r(/posts/.+) PostsController.action(:destroy).call(env) else [404, {'Content-Type': 'text-plain', ...}, ['Not Found!']] end end end https://youtu.be/lEC-QoZeBkM

Slide 36

Slide 36 text

app/controllers/hello_controller.rb Rails.application.routes.draw do get '/hello' => HelloWorld.new get '/hello' => ->(env) { [200, {'Content-Type': 'text/plain'}, ['Hello World!'] } # redirect(...) returns a Rack app! get '/' => redirect('/hello') mount Sidekiq::Web, at: '/sidekiq' end config/routes.rb

Slide 37

Slide 37 text

app/controllers/hello_controller.rb Rails.application.routes.draw do get '/posts' => PostsController.action(:index) get '/posts/new' => PostsController.action(:new) post '/posts' => PostsController.action(:create) get '/posts/:id' => PostsController.action(:show) get '/posts/:id/edit' => PostsController.action(:edit) put '/posts/:id' => PostsController.action(:update) delete '/posts/:id' => PostsController.action(:destroy) end config/routes.rb

Slide 38

Slide 38 text

app/controllers/hello_controller.rb Hello World http://skylight.io/hello app/controllers/hello_controller.rb class HelloController < ActionController::Base def index # ...do stuff here... render plain: 'Hello World' end end app/controllers/hello_controller.rb

Slide 39

Slide 39 text

app/controllers/hello_controller.rb $ Terminal bin/rails middleware use Skylight::Middleware use Rack::Sendfile use ActionDispatch::Executor use ActiveSupport::Cache::Strategy::LocalCache::Middleware use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use ActionDispatch::RemoteIp use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use ActionDispatch::Callbacks use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ContentSecurityPolicy::Middleware use Rack::Head use Rack::ConditionalGet use Rack::ETag use Rack::TempfileReaper run Blorgh::Application.routes

Slide 40

Slide 40 text

app/controllers/hello_controller.rb class ActionController::Base def self.action(name) ->(env) { request = ActionDispatch::Request.new(env) response = ActionDispatch::Response.new(request) controller = self.new(request, response) controller.process_action(name) response.to_a } end attr_reader :request, :response, :params def initialize(request, response) @request = request @response = response @params = request.params end def process_action(name) event = 'process_action.action_controller' payload = { controller: self.class.name, action: action_name, # ... } ActiveSupport::Notifications.instrument(event, payload) do self.send(name) end end end rails/actionpack/lib/action_controller/base.rb

Slide 41

Slide 41 text

app/controllers/hello_controller.rb skylight.io

Slide 42

Slide 42 text

app/controllers/hello_controller.rb skylight.io

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

No content