Class: CurrentScope::Role
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- CurrentScope::Role
- Defined in:
- app/models/current_scope/role.rb
Overview
A named, editable bundle of permissions — a row, not a class. The same role means the same permission set whether held org-wide or scoped to a single record; only the reach differs.
Instance Attribute Summary collapse
-
#permission_keys_change ⇒ Object
readonly
The grid diff computed by the last save: { added: [...], removed: [...], rejected: [...] }.
Instance Method Summary collapse
-
#assign_permission_keys(keys, scrub: false) ⇒ Object
ponytail: one implementation, two intents — the setter is the strict front door, this is the same staging with the scrub opt-in named at the call site.
- #grants?(permission_key) ⇒ Boolean
- #permission_keys ⇒ Object
-
#permission_keys=(keys) ⇒ Object
Stages a replacement permission set.
- #reload ⇒ Object
Instance Attribute Details
#permission_keys_change ⇒ Object (readonly)
The grid diff computed by the last save:
{ added: [...], removed: [...], rejected: [...] }. Empty arrays on a no-op
save; nil when no grid was staged (a programmatic save that never set
permission_keys). added/removed describe what actually persisted;
rejected names keys the scrub path threw away, so a caller that opted
into silence can still log it. Controllers read this to record the change
— the model itself records nothing (seeds must stay silent).
22 23 24 |
# File 'app/models/current_scope/role.rb', line 22 def @permission_keys_change end |
Instance Method Details
#assign_permission_keys(keys, scrub: false) ⇒ Object
ponytail: one implementation, two intents — the setter is the strict front door, this is the same staging with the scrub opt-in named at the call site.
scrub: true is the ONLY sanctioned silent drop, and it exists for one
real case: a controller was removed, so a role still holds keys that no
longer route. Cleaning those up is legitimate and shouldn't require the
operator to name every dead key. Everything else — typos, unrouted
programmatic grants, the never-routed break-glass permission — is a
mistake, and a security-grant API must not swallow mistakes.
51 52 53 54 55 56 57 58 59 60 |
# File 'app/models/current_scope/role.rb', line 51 def (keys, scrub: false) # Literal `true` only. Ruby truthiness would let the string "false" — or # any params/config value that found its way here — silently disable the # strict path, which is the exact hole this API exists to close. The # escape hatch opens for a caller that means it, not for one that passed # something along. @scrub_permission_keys = scrub == true # Blank entries are the grid's hidden-field padding, not typos (R2). @pending_permission_keys = Array(keys).map(&:to_s).reject(&:blank?).uniq end |
#grants?(permission_key) ⇒ Boolean
24 25 26 |
# File 'app/models/current_scope/role.rb', line 24 def grants?() .exists?(permission_key: ) end |
#permission_keys ⇒ Object
28 29 30 |
# File 'app/models/current_scope/role.rb', line 28 def @pending_permission_keys || .pluck(:permission_key) end |
#permission_keys=(keys) ⇒ Object
Stages a replacement permission set. STRICT: a key that isn't in the route-derived catalog makes the record invalid rather than disappearing. This is the mass-assignment writer (update!, strong params, the role grid), so it is deliberately the strict one — the scrub escape hatch must never be reachable from form params.
37 38 39 |
# File 'app/models/current_scope/role.rb', line 37 def (keys) (keys, scrub: false) end |
#reload ⇒ Object
62 63 64 65 66 |
# File 'app/models/current_scope/role.rb', line 62 def reload(...) @pending_permission_keys = nil @scrub_permission_keys = false super end |