Class: Everywhere::RequestContext

Inherits:
Object
  • Object
show all
Defined in:
lib/everywhere/request_context.rb

Overview

What a per-request hook — the tab bar block, the current-user resolver — gets handed instead of a bare request.

It exists because the raw request isn't the same object on every path: Rails apps reach the mobile config endpoint through MobileConfigsController with an ActionDispatch::Request (signed/encrypted cookie jar), Sinatra and Hanami apps through MobileConfigEndpoint with a Rack::Request (plain cookie hash). A block written against one used to break on the other; #session and #cookies here read the same on both.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request, platform: nil, config: nil) ⇒ RequestContext

Returns a new instance of RequestContext.



27
28
29
30
31
# File 'lib/everywhere/request_context.rb', line 27

def initialize(request, platform: nil, config: nil)
  @request = request
  @platform = platform&.to_s
  @config = config
end

Instance Attribute Details

#configObject (readonly)

The app's Everywhere::Config. nil outside the mobile config endpoint.



25
26
27
# File 'lib/everywhere/request_context.rb', line 25

def config
  @config
end

#platformObject (readonly)

"ios" or "android" — which shell is asking. nil outside the mobile config endpoint.



22
23
24
# File 'lib/everywhere/request_context.rb', line 22

def platform
  @platform
end

#requestObject (readonly)

The framework-native request, for anything this class doesn't wrap (Warden lives at request.env["warden"], for one).



18
19
20
# File 'lib/everywhere/request_context.rb', line 18

def request
  @request
end

Instance Method Details

#android?Boolean

Returns:

  • (Boolean)


34
# File 'lib/everywhere/request_context.rb', line 34

def android? = platform == "android"

#cookiesObject

Cookies. Rails' jar when the request carries one, so cookies.signed[…] and cookies.encrypted[…] work; Rack's name => value hash otherwise. Both answer cookies[:name], which is the common case.



47
48
49
50
51
52
53
54
55
# File 'lib/everywhere/request_context.rb', line 47

def cookies
  return @cookies if defined?(@cookies)

  @cookies =
    if request.respond_to?(:cookie_jar) then request.cookie_jar
    elsif request.respond_to?(:cookies) then request.cookies
    else {}
    end
end

#current_userObject

Whoever Everywhere.current_user resolves for this request — nil when no resolver is registered, so a hook that branches on it degrades to "signed out" rather than raising. Memoized: resolvers hit the database, and the tab block is free to ask several times.



61
62
63
64
65
# File 'lib/everywhere/request_context.rb', line 61

def current_user
  return @current_user if defined?(@current_user)

  @current_user = Everywhere.resolve_current_user(self)
end

#ios?Boolean

Returns:

  • (Boolean)


33
# File 'lib/everywhere/request_context.rb', line 33

def ios? = platform == "ios"

#sessionObject

The session hash, or {} when the app runs no session middleware (and on the bare-env fallback, where request is a Hash rather than a Request).



38
39
40
41
42
# File 'lib/everywhere/request_context.rb', line 38

def session
  return @session if defined?(@session)

  @session = (request.session if request.respond_to?(:session)) || {}
end

#signed_in?Boolean

Returns:

  • (Boolean)


67
# File 'lib/everywhere/request_context.rb', line 67

def signed_in? = !current_user.nil?

#tab(name) ⇒ Object

A tab declared in config/everywhere.yml, by name, resolved for this platform — including visible: false ones, which is the point: declare a tab so the build validates its icon and bakes nothing, then add it back here for the users who should see it.

Everywhere.tabs do |tabs, ctx|
ctx.current_user.admin? ? tabs + [ctx.tab("Admin")] : tabs
end

Raises on an unknown name rather than returning nil: a typo would otherwise drop the tab silently, and this fails in the endpoint where the message can name it.

Raises:



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/everywhere/request_context.rb', line 81

def tab(name)
  unless config && platform
    raise Error, "RequestContext#tab needs the app config — it's available " \
                 "inside an Everywhere.tabs block, not to a standalone context"
  end

  declared = config.tabs_for(platform, include_hidden: true)
  wanted = name.to_s
  found = declared.find { |tab| tab["title"] == wanted } ||
          declared.find { |tab| tab["title"].to_s.casecmp?(wanted) }
  return found if found

  raise Error, "no tab named #{wanted.inspect} in config/everywhere.yml — " \
               "declared: #{declared.map { |tab| tab["title"] }.inspect}"
end