Module: CurrentScope::Permissions

Included in:
Context
Defined in:
lib/current_scope/permissions.rb

Overview

The portable authorization mixin. Works anywhere — controllers, views, components, POROs — because the subject comes from the ambient CurrentScope::Current context rather than being threaded through calls. Everything delegates to the one resolver, so a view can never disagree with the controller gate.

allowed_to?(:approve, report)          # key derived from the record
allowed_to?(:create, Report)           # class works for collection actions
allowed_to?("admin/reports#approve")   # explicit full key
allowed_to?(:index, controller: "reports")

Instance Method Summary collapse

Instance Method Details

#allowed_to?(action, record = nil, controller: nil) ⇒ Boolean

Returns:

  • (Boolean)


13
14
15
16
17
# File 'lib/current_scope/permissions.rb', line 13

def allowed_to?(action, record = nil, controller: nil)
  controller ||= controller_path if respond_to?(:controller_path)
  CurrentScope.allowed?(action, subject: current_scope_user, record: record,
    controller_path: controller, actor: current_scope_actor)
end

#current_scope_actorObject

The REAL actor behind the request (never nil when a subject is set — it falls back to the subject). Read this for attribution, not Current.



46
47
48
# File 'lib/current_scope/permissions.rb', line 46

def current_scope_actor
  CurrentScope::Current.actor
end

#current_scope_userObject



40
41
42
# File 'lib/current_scope/permissions.rb', line 40

def current_scope_user
  CurrentScope::Current.user
end

#impersonating?Boolean

True only while a distinct real actor stands behind the effective subject (act-as). Views use it as the read-only-state signal.

Returns:

  • (Boolean)


52
53
54
55
# File 'lib/current_scope/permissions.rb', line 52

def impersonating?
  CurrentScope::Current.user.present? &&
    CurrentScope::Current.actor != CurrentScope::Current.user
end

#scope_for(model, permission: nil) ⇒ Object

The list-side companion to allowed_to?: "which records of model may the effective subject act on?". Same grants, keys, and fail-closed rules as the gate, so a list can't drift from the per-record decision. Returns a chainable relation (.where/.order/.page on it). permission defaults to the model's index context and accepts a bare action or a full key.

scope_for(Project)                 # projects#index — what a list shows
scope_for(Report, permission: :approve)
scope_for(Report, permission: "admin/reports#approve")


28
29
30
31
32
33
34
35
36
37
38
# File 'lib/current_scope/permissions.rb', line 28

def scope_for(model, permission: nil)
  # Derive the key exactly like allowed_to? — including controller_path, so a
  # namespaced controller's list resolves to the same key as its gate
  # (admin/reports#index, not reports#index) and the two never drift.
  controller = controller_path if respond_to?(:controller_path)
  CurrentScope.scope_for(
    subject: current_scope_user,
    model: model,
    permission: CurrentScope.permission_key(permission || :index, record: model, controller_path: controller)
  )
end