Module: Rhino::Context

Defined in:
lib/rhino/context.rb

Overview

Ambient tenant context resolver.

Reads the current user/organization from RequestStore by default (request-time context set by the controller before_actions), but can be overridden for the duration of a block via with — used by the explicit query builder so jobs, rake tasks, and tests can query without a route.

Class Method Summary collapse

Class Method Details

.organization ⇒ Object

The active organization: the explicit override if one is in effect, else the request-time organization from RequestStore.



15
16
17
18
19
20
21
# File 'lib/rhino/context.rb', line 15

def organization
  if store.key?(:rhino_organization)
    store[:rhino_organization]
  elsif defined?(RequestStore)
    RequestStore.store[:rhino_organization]
  end
end

.route_group ⇒ Object

The active route group: the explicit override if one is in effect (set by Rhino.in_route_group), else the group stashed into RequestStore by Rhino's own controllers and by Rhino::RouteGroupContext in custom ones.

Unlike user/organization, an override never erases the request's group — with only installs a non-nil one — so Rhino.for_user(u).query(M) inside a non-tenant request keeps that request's group.



40
41
42
43
44
45
# File 'lib/rhino/context.rb', line 40

def route_group
  value = store[:rhino_route_group]
  value = RequestStore.store[:rhino_route_group] if value.nil? && defined?(RequestStore)

  value.nil? || value.to_s.empty? ? nil : value.to_s
end

.store ⇒ Object

Fiber-local override store for the active explicit context.



124
125
126
# File 'lib/rhino/context.rb', line 124

def store
  Thread.current[:rhino_context_override] ||= {}
end

.user ⇒ Object

The active user: the explicit override if one is in effect, else the request-time user from RequestStore.



25
26
27
28
29
30
31
# File 'lib/rhino/context.rb', line 25

def user
  if store.key?(:rhino_current_user)
    store[:rhino_current_user]
  elsif defined?(RequestStore)
    RequestStore.store[:rhino_current_user]
  end
end

.with(user:, organization:, route_group: nil) ⇒ Object

Run block with the given user/organization installed into RequestStore. Snapshots the prior RequestStore user+org, sets the new ones, yields, and restores the snapshot in an ensure. Returns the block's value.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/rhino/context.rb', line 50

def with(user:, organization:, route_group: nil)
  return yield unless defined?(RequestStore)

  had_user = RequestStore.store.key?(:rhino_current_user)
  had_org  = RequestStore.store.key?(:rhino_organization)
  prev_user = RequestStore.store[:rhino_current_user]
  prev_org  = RequestStore.store[:rhino_organization]

  # A route group is only ever ADDED, never cleared: with no explicit group
  # the request's own one (if any) stays in effect.
  had_group  = RequestStore.store.key?(:rhino_route_group)
  prev_group = RequestStore.store[:rhino_route_group]
  had_override_group  = store.key?(:rhino_route_group)
  prev_override_group = store[:rhino_route_group]

  # Track the active override so Context.user/organization prefer it even when
  # the passed value is nil (distinguishing "explicitly nil" from "absent").
  had_override_user = store.key?(:rhino_current_user)
  had_override_org  = store.key?(:rhino_organization)
  prev_override_user = store[:rhino_current_user]
  prev_override_org  = store[:rhino_organization]

  RequestStore.store[:rhino_current_user] = user
  RequestStore.store[:rhino_organization] = organization
  store[:rhino_current_user] = user
  store[:rhino_organization] = organization

  if route_group
    RequestStore.store[:rhino_route_group] = route_group.to_s
    store[:rhino_route_group] = route_group.to_s
  end

  begin
    yield
  ensure
    if had_user
      RequestStore.store[:rhino_current_user] = prev_user
    else
      RequestStore.store.delete(:rhino_current_user)
    end
    if had_org
      RequestStore.store[:rhino_organization] = prev_org
    else
      RequestStore.store.delete(:rhino_organization)
    end

    if had_override_user
      store[:rhino_current_user] = prev_override_user
    else
      store.delete(:rhino_current_user)
    end
    if had_override_org
      store[:rhino_organization] = prev_override_org
    else
      store.delete(:rhino_organization)
    end

    if route_group
      if had_group
        RequestStore.store[:rhino_route_group] = prev_group
      else
        RequestStore.store.delete(:rhino_route_group)
      end

      if had_override_group
        store[:rhino_route_group] = prev_override_group
      else
        store.delete(:rhino_route_group)
      end
    end
  end
end