Rack


...or how to build your own Ruby on Rails





by Hubert Łępicki
@hubertlepicki

     

What is Rack?



Rack: a Ruby Webserver Interface


Rack provides a minimal interface between webservers supporting Ruby and Ruby frameworks.

    Before Rack





    remember "apache proxy to cluster of mongrels"?

    Different solutions

    • (F)CGI
    • mod_rails
    • mongrel handler
    • apache proxy + cluster of mongrels
    • meanwhile, Python already had WSGI



    Supported servers



    • Apache/Passenger
    • Nginx/Passenger
    • Puma
    • Unicorn
    • Webrick ;)
    • Thin
    • Rainbows
    • name it!

    The interface



    describe 'rack interface' do it 'should respond to call and accept hash' it 'should return [status, headers, and chunks of body]'end

    Interface as lambda

    lambda do |env|
      body = "Hello, World!"
        [ 200,    { "Content-Type" =>  "text/plain",      "Content-Length" => body.length.to_s },           [body]  ]
    end

    Interface as an object


     class RackAwesomeMiddleware
    def call(env) body = "Rack is awesome!"
    [ 200,  {"Content-Type" => "text/plain",  "Content-Length" => body.length.to_s}, [body] ] end
    end


    Stack of middleware



    Rackup file config.ru


    use Rack::Reloader, 0
    use Rack::ContentLength
    
    app = proc do |env|
      [ 200, {'Content-Type' => 'text/plain'}, ["a"] ]
    end run app
    $ rackup config.ru # starts the app

    Interacting with layers below (above?)


    class AwesomeMiddleware  def initialize app    @app = app  end
    def call(env) @app.call env endend

    Modify the response of other layer


    class AwesomeMiddleware  def initialize app    @app = app  end
    def call(env) res = @app.call(env) res[1]["Server"] = "Awesome Server" res endend

      Modify environment


      class AwesomeMiddleware  def initialize app    @app = app  end
      def call(env) env["RAILS_ENV"] = 'awesome' @app.call env endend

      Rails on Rack


      require ::File.expand_path('../config/environment',  __FILE__)
      run Rails.application 

      Rails on Rack

       # config/environments/staging.rb
      config.middleware.insert_before(::Rack::Runtime,  "::BasicAuthMiddleware", "Staging") do |u, p|
      u == 'secret' && p == 'password'
      end

      Configuring Rack middleware

      class ConfigurableMiddleware  def initialize(app, &block)     config = OpenStruct.new     yield config     ...  endend
      # confug.ru / config/environments/*.rbconfig.middleware.use 'ConfigurableMiddleware' do |config| config.foo = 'bar'end

      Examples

      Rack::Lint
      Rack::Cache
      Rack::Logger
      Rack::Static
      Rack::Auth::Basic
      Rack::TimeZone
      Rack::Locale
      Rack::Profiler
      Faye
      websocket-rack

      Rails middleware stack

      use Rack::Sendfile
      use ActionDispatch::Static
      use Rack::Lock
      use Rack::Runtime
      use Rack::MethodOverride
      use ActionDispatch::RequestId
      use Rails::Rack::Logger
      use ActionDispatch::ShowExceptions
      use ActionDispatch::DebugExceptions
      use ActionDispatch::RemoteIp
      use ActionDispatch::Reloader
      use ActionDispatch::Callbacks
      use ActiveRecord::Migration::CheckPending
      use ActiveRecord::ConnectionAdapters::ConnectionManagement
      use ActiveRecord::QueryCache
      use ActionDispatch::Cookies
      use ActionDispatch::Session::CookieStore
      use ActionDispatch::Flash
      use ActionDispatch::ParamsParser
      use Rack::Head
      use Rack::ConditionalGet
      use Rack::ETag
      run MyApp::Application.routes 

      Links and stuff


      "Rails on Rack" in Rails guides
      http://guides.rubyonrails.org/rails_on_rack.html

      "Build your own framework with Rack"
      http://isotope11.com/blog/build-your-own-web-framework-with-rack-and-ruby-part-1

      "Introduction to Rack middleware"
      http://www.amberbit.com/blog/2011/07/13/introduction-to-rack-middleware/
      Made with Slides.com