module Hanami::Action::Rack

Rack integration API

@since 0.1.0

Constants

CONTENT_LENGTH

The Content-Length HTTP header

@since 1.0.0 @api private

DEFAULT_REQUEST_ID_LENGTH

The default HTTP Request ID length

@since 0.3.0 @api private

@see Hanami::Action::Rack#request_id

DEFAULT_RESPONSE_BODY

The default Rack response body

@since 0.1.0 @api private

DEFAULT_RESPONSE_CODE

The default HTTP response code

@since 0.1.0 @api private

FILE_SYSTEM_ROOT

This is the root directory for `#unsafe_send_file`

@since 1.3.3 @api private

@see unsafe_send_file

HEAD request

@since 0.3.2 @api private

NOT_FOUND

Not Found

@since 1.0.0 @api private

REQUEST_METHOD

The request method

@since 0.3.2 @api private

RESPONSE_BODY

Rack SPEC response body

@since 1.0.0 @api private

RESPONSE_CODE

Rack SPEC response code

@since 1.0.0 @api private

RESPONSE_HEADERS

Rack SPEC response headers

@since 1.0.0 @api private

ROUTER_PARSED_BODY

The key that returns router parsed body from the Rack env

X_CASCADE

The non-standard HTTP header to pass the control over when a resource cannot be found by the current endpoint

@since 1.0.0 @api private

Public Class Methods

included(base) click to toggle source

Override Ruby's hook for modules. It includes basic Hanami::Action modules to the given class.

@param base [Class] the target action

@since 0.1.0 @api private

@see www.ruby-doc.org/core-2.1.2/Module.html#method-i-included

# File lib/hanami/action/rack.rb, line 103
def self.included(base)
  base.class_eval do
    extend ClassMethods
    prepend InstanceMethods
  end
end

Protected Instance Methods

headers() click to toggle source

Gets the headers from the response

@return [Hash] the HTTP headers from the response

@since 0.1.0

@example

require 'hanami/controller'

class Show
  include Hanami::Action

  def call(params)
    # ...
    self.headers            # => { ... }
    self.headers.merge!({'X-Custom' => 'OK'})
  end
end
# File lib/hanami/action/rack.rb, line 204
def headers
  @headers
end
parsed_request_body() click to toggle source

Return parsed request body

@deprecated

# File lib/hanami/action/rack.rb, line 259
def parsed_request_body
  Hanami::Utils::Deprecation.new('#parsed_request_body is deprecated and it will be removed in future versions')
  @_env.fetch(ROUTER_PARSED_BODY, nil)
end
request() click to toggle source

Returns a Hanami specialized rack request

@return [Hanami::Action::Request] The request

@since 0.3.1

@example

require 'hanami/controller'

class Create
  include Hanami::Action

  def call(params)
    ip     = request.ip
    secure = request.ssl?
  end
end
# File lib/hanami/action/rack.rb, line 252
def request
  @request ||= ::Hanami::Action::Request.new(@_env)
end
request_id() click to toggle source

Calculates an unique ID for the current request

@return [String] The unique ID

@since 0.3.0

# File lib/hanami/action/rack.rb, line 230
def request_id
  # FIXME make this number configurable and document the probabilities of clashes
  @request_id ||= SecureRandom.hex(DEFAULT_REQUEST_ID_LENGTH)
end
response() click to toggle source

Returns a serialized Rack response (Array), according to the current

status code, headers, and body.

@return [Array] the serialized response

@since 0.1.0 @api private

@see Hanami::Action::Rack::DEFAULT_RESPONSE_CODE @see Hanami::Action::Rack::DEFAULT_RESPONSE_BODY @see Hanami::Action::Rack#status= @see Hanami::Action::Rack#headers @see Hanami::Action::Rack#body=

# File lib/hanami/action/rack.rb, line 221
def response
  [ @_status || DEFAULT_RESPONSE_CODE, headers, @_body || DEFAULT_RESPONSE_BODY.dup ]
end

Private Instance Methods

_send_file(response) click to toggle source

@since 1.0.0 @api private

# File lib/hanami/action/rack.rb, line 394
def _send_file(response)
  headers.merge!(response[RESPONSE_HEADERS])

  if response[RESPONSE_CODE] == NOT_FOUND
    headers.delete(X_CASCADE)
    headers.delete(CONTENT_LENGTH)
    halt NOT_FOUND
  else
    # FIXME: this is a fix for https://github.com/hanami/controller/issues/240
    # It's here to maintain the backward compat with 1.1, as we can't remove `#halt`
    # We should review the workflow for 2.0, because I don't like callbacks to be referenced from here.
    _run_after_callbacks(params)
    halt response[RESPONSE_CODE], response[RESPONSE_BODY]
  end
end
body=(body) click to toggle source

Sets the body of the response

@param body [String] the body of the response @return [void]

@since 0.1.0

@example

require 'hanami/controller'

class Show
  include Hanami::Action

  def call(params)
    # ...
    self.body = 'Hi!'
  end
end
# File lib/hanami/action/rack.rb, line 306
def body=(body)
  body   = Array(body) unless body.respond_to?(:each)
  @_body = body
end
head?() click to toggle source

Check if the current request is a HEAD

@return [TrueClass,FalseClass] the result of the check

@since 0.3.2

# File lib/hanami/action/rack.rb, line 380
def head?
  request_method == HEAD
end
request_method() click to toggle source

NOTE: Hanami::Action::CSRFProtection (hanamirb gem) depends on this.

@api private @since 0.4.4

# File lib/hanami/action/rack.rb, line 388
def request_method
  @_env[REQUEST_METHOD]
end
send_file(path) click to toggle source

Send a file as response.

<tt>This method only sends files from the public directory</tt>

It automatically handle the following cases:

* <tt>Content-Type</tt> and <tt>Content-Length</tt>
* File Not found (returns a 404)
* Conditional GET (via <tt>If-Modified-Since</tt> header)
* Range requests (via <tt>Range</tt> header)

@param path [String, Pathname] the body of the response @return [void]

@since 0.4.3

@example

require 'hanami/controller'

class Show
  include Hanami::Action

  def call(params)
    # ...
    send_file Pathname.new('path/to/file')
  end
end
# File lib/hanami/action/rack.rb, line 337
def send_file(path)
  _send_file(
    File.new(path, self.class.configuration.public_directory).call(@_env)
  )
end
status=(status) click to toggle source

Sets the HTTP status code for the response

@param status [Fixnum] an HTTP status code @return [void]

@since 0.1.0

@example

require 'hanami/controller'

class Create
  include Hanami::Action

  def call(params)
    # ...
    self.status = 201
  end
end
# File lib/hanami/action/rack.rb, line 284
def status=(status)
  @_status = status
end
unsafe_send_file(path) click to toggle source

Send a file as response from anywhere in the file system.

@see Hanami::Action::Rack#send_file

@param path [String, Pathname] path to the file to be sent @return [void]

@since 1.0.0

@example

require 'hanami/controller'

class Show
  include Hanami::Action

  def call(params)
    # ...
    unsafe_send_file Pathname.new('/tmp/path/to/file')
  end
end
# File lib/hanami/action/rack.rb, line 363
def unsafe_send_file(path)
  directory = if Pathname.new(path).relative?
                self.class.configuration.root_directory
              else
                FILE_SYSTEM_ROOT
              end

  _send_file(
    File.new(path, directory).call(@_env)
  )
end