Class: CurrentScope::RolesController
- Inherits:
-
ApplicationController
- Object
- ApplicationController
- CurrentScope::RolesController
- Defined in:
- app/controllers/current_scope/roles_controller.rb
Constant Summary collapse
- ADD_LIMIT =
Who holds this role — the role-side complement to the subjects page. Org-wide holders (this role IS their one org-wide role) and per-record scoped holders, plus a capped list of subjects to add from here.
100
Instance Method Summary collapse
- #create ⇒ Object
- #destroy ⇒ Object
- #edit ⇒ Object
- #index ⇒ Object
- #members ⇒ Object
- #new ⇒ Object
- #update ⇒ Object
Instance Method Details
#create ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'app/controllers/current_scope/roles_controller.rb', line 12 def create @role = Role.new(role_params) saved = false Role.transaction do saved = @role.save # Fold the initial permission set into the create event — no separate # grid-diff event for a brand-new role. if saved Event.record!(event: "role.created", target: @role, details: { name: @role.name, full_access: @role.full_access?, permission_keys: @role. }) end end if saved redirect_to edit_role_path(@role), notice: "Role created." else render :new, status: :unprocessable_entity end end |
#destroy ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'app/controllers/current_scope/roles_controller.rb', line 98 def destroy refused = false Role.transaction do lock_full_access_console_state! role = Role.lock.find(params[:id]) if would_lock_console_by_removing_role?(role) refused = true else # Snapshot WITHOUT polymorphic includes — includes(:subject)/:resource # can raise NameError for stale types at preload (members page avoids # this for the same reason). Resolve each row inside the helpers. org_removed = role.role_assignments.to_a scoped_revoked = role.scoped_role_assignments.to_a role.destroy! Event.record!(event: "role.deleted", target: role, details: { name: role.name }) org_removed.each do |a| Event.record!(event: "org_role.removed", target: cascade_subject(a), details: { role: role.name }) end scoped_revoked.each do |a| Event.record!(event: "scoped_role.revoked", target: cascade_subject(a), details: { role: role.name, resource: cascade_resource_label(a) }) end end end if refused redirect_to roles_path, alert: "Refusing to delete this full-access role — it is the last one held by any " \ "subject and would lock everyone out of this UI. Grant full access to " \ "another subject first, then retry." return end redirect_to roles_path, notice: "Role deleted." end |
#edit ⇒ Object
33 34 35 |
# File 'app/controllers/current_scope/roles_controller.rb', line 33 def edit @role = Role.find(params[:id]) end |
#index ⇒ Object
3 4 5 6 |
# File 'app/controllers/current_scope/roles_controller.rb', line 3 def index # Includes for delete-confirm holder counts (cascade warning). @roles = Role.order(:name).includes(:role_assignments, :scoped_role_assignments) end |
#members ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'app/controllers/current_scope/roles_controller.rb', line 42 def members @role = Role.find(params[:id]) # No polymorphic includes: eager-loading a stale/renamed subject_type or # resource_type raises NameError. Lazy-load per row and label defensively # in the view (current_scope_holder_* helpers), like the audit ledger does. @org_holders = RoleAssignment.where(role: @role).to_a @scoped_holders = ScopedRoleAssignment.where(role: @role).to_a # Exclude via a subquery, not a plucked Ruby array, so a role with many # holders doesn't build a huge NOT IN bind list. held = RoleAssignment.where(role: @role, subject_type: subject_class.name).select(:subject_id) remaining = subject_class.where.not(id: held).order(:id) @candidates = remaining.limit(ADD_LIMIT).to_a @more_candidates = remaining.offset(ADD_LIMIT).exists? end |
#new ⇒ Object
8 9 10 |
# File 'app/controllers/current_scope/roles_controller.rb', line 8 def new @role = Role.new end |
#update ⇒ Object
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 |
# File 'app/controllers/current_scope/roles_controller.rb', line 58 def update permitted = role_params previous_name = nil saved = false refused = false # Lock full-access roles + holders inside the write transaction so two # concurrent demotions of the last held full-access roles cannot both pass # a pre-transaction check and then both commit. Role.transaction do # Lock FA console state before the target role so concurrent demote/delete # of two FA roles cannot invert lock order (roles first, then assignments). lock_full_access_console_state! @role = Role.lock.find(params[:id]) if demoting_would_lock_console?(@role, permitted) refused = true else previous_name = @role.name previous_full_access = @role.full_access? saved = @role.update(permitted) record_role_update(@role, previous_name, previous_full_access) if saved end end if refused redirect_to edit_role_path(@role), alert: "Refusing to remove full access — this is the last full-access role " \ "any subject holds and would lock everyone out of this UI. Grant " \ "full access to another subject first, then retry." return end if saved redirect_to roles_path, notice: "Role updated." else render :edit, status: :unprocessable_entity end end |