class Rack::State

The Middleware Interface

Stores and manages the state of a single object on the server and sets the state token in a client cookie. Multiple State instances may be utilized to manage multiple states, each with different storage adapters and options.

State initializes Manager, which contains the API.

Constants

VERSION

Public Class Methods

new(app, options = {}) click to toggle source

Middleware Options

store

Instance of the storage adapter. See Rack::State::Store for available adapters. The default is Store::Memory.

key

Client cookie name and Rack environment key suffix. For example, the key “token” sets a cookie named “token” and the environment key to “rack.state.token”. Therefore, the application can access the State::Manager instance at env["rack.state.token"]. The default is “token”.

domain, path, max_age, expires, secure, httponly

Standard cookie options supported by Rack. None are set by default; therefore, the state will be valid for the session only on the domain and path in which it was set and available over unsecured connections.

# File lib/rack/state.rb, line 50
def initialize(app, options = {})
  @app = app
  @options = options
  @store = options.delete(:store) || Store::Memory.new
  @key = options.delete(:key) || 'token'
  @skey = "rack.state.#{@key}"
end

Public Instance Methods

call(env) click to toggle source
# File lib/rack/state.rb, line 58
def call(env)
  request = Request.new(env)

  # TODO filter on UA: if bot, set state to some temp in-memory hash???

  # TODO also try not to send cookie back if token stayed the same.
  # after fetching the object from storage, note the last-modified time.
  # Then when it comes time to `state.finish`, if the cook isn't past the
  # "refresh" time in seconds, don't send the cookie. Will need to add the
  # refresh option.

  if request.path =~ /^#{@options[:path]}/
    token = request.cookies.fetch(@key, nil)
    state = env[@skey] = Manager.new(@store, token, @key, @options)
    status, headers, body = @app.call(env)
    resp = Response.new(body, status, headers)
    state.finish(resp)
    resp.finish
  else
    @app.call(env)
  end
end