Class: CurrentScope::ScopedRoleAssignmentsController

Inherits:
ApplicationController show all
Defined in:
app/controllers/current_scope/scoped_role_assignments_controller.rb

Overview

Grants/revokes a role on ONE specific record. new is a guided cascade (Role → Subject → Resource type → Record); create grants; destroy revokes. A record page can still deep-link straight to a target with:

current_scope.new_scoped_role_assignment_path(resource_gid: record.to_gid)

Constant Summary collapse

SCAN_CAP =

ponytail: record search scans only the first SCAN_CAP rows of a type and renders at most DISPLAY_LIMIT matches. current_scope_label is a Ruby method with no backing column, so the filter runs in Ruby (not SQL LIKE); a dedicated indexed label column is the upgrade path for large tables.

500
DISPLAY_LIMIT =
50
SEARCH_THRESHOLD =

Offer a search box (instead of listing every record) past this many.

20

Instance Method Summary collapse

Instance Method Details

#createObject



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'app/controllers/current_scope/scoped_role_assignments_controller.rb', line 30

def create
  resource = GlobalID::Locator.locate(params.expect(:resource_gid))
  role = Role.find(params.expect(:role_id))
  subjects = locate_subjects()
  if subjects.empty?
    redirect_to subjects_path, alert: "No subjects selected."
    return
  end

  granted = 0
  # One transaction for the whole bulk grant — all-or-nothing, like the
  # org-wide sibling. A per-subject savepoint (grant_one) absorbs the
  # concurrent-duplicate race without poisoning the outer transaction, while
  # a genuine RecordInvalid rolls the entire batch back.
  ScopedRoleAssignment.transaction do
    subjects.each { |subject| granted += 1 if grant_one(subject, resource, role) }
  end

  redirect_to subjects_path, notice: grant_notice(granted, subjects.size)
rescue ActiveRecord::RecordInvalid => e
  redirect_to subjects_path, alert: e.message
rescue ActiveRecord::RecordNotFound, NameError
  redirect_to subjects_path,
              alert: "Couldn't grant that scoped role — the subject, role, or record is no longer available."
end

#destroyObject



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'app/controllers/current_scope/scoped_role_assignments_controller.rb', line 56

def destroy
  assignment = ScopedRoleAssignment.find(params[:id])
  subject, role = assignment.subject, assignment.role

  ScopedRoleAssignment.transaction do
    assignment.destroy!
    Event.record!(event: "scoped_role.revoked", target: subject,
                  details: { role: role.name, resource: assignment_resource_label(assignment) })
  end
  redirect_to subjects_path, notice: "Scoped role revoked."
rescue ActiveRecord::RecordNotFound
  redirect_to subjects_path, notice: "That scoped role was already revoked."
end

#newObject



17
18
19
20
21
22
23
24
25
26
27
28
# File 'app/controllers/current_scope/scoped_role_assignments_controller.rb', line 17

def new
  @assignment = ScopedRoleAssignment.new
  @roles = Role.order(:name)
  @subjects = subject_class.order(:id)
  @scopeable = CurrentScope.scopeable_resources
  @bulk_subjects = resolve_bulk_subjects # [] unless a multi-select bulk grant

  @resource = deep_linked_resource
  @resource_type = resolve_type(params[:resource_type]) || @resource&.class
  @searchable = searchable?(@resource_type)
  @records = candidate_records(@resource_type, params[:q])
end