Skip to content

Refactor RequestsController and delegate logic to RequestService#477

Merged
cycomachead merged 7 commits into
mainfrom
cycomachead/164-refactor-requests-controller/1
Jul 4, 2026
Merged

Refactor RequestsController and delegate logic to RequestService#477
cycomachead merged 7 commits into
mainfrom
cycomachead/164-refactor-requests-controller/1

Conversation

@cycomachead

Copy link
Copy Markdown
Contributor

General Info

Changes

Refactors RequestsController to remove unnecessary indirection, delegate business logic to models, and improve test coverage. RequestService — a set of class methods with zero test coverage that each returned a redirect hash the controller then re-interpreted — has been deleted entirely, with its logic folded into idiomatic before_action filters and model methods.

Key changes:

  • Removed RequestService: Logic moved into controller filters that redirect directly, delegating decisions to models rather than bouncing through a service hash.
  • New model methods: Course#extensions_enabled?, Request#pending?, Request.pending scope, and Request#approve_by(acting_user) encapsulate logic that was previously scattered across the controller and duplicated in places.
  • Replaced @role string comparisons: Permission checks now ask the course directly (course_staff? / course_student?) instead of comparing a @role string. @role is still assigned by ApplicationController#set_course since the shared view layer still depends on it.
  • Simplified before_action chain: set_course_role_from_settings + authenticate_course collapsed into the existing ApplicationController#set_course + a small set_form_settings filter.
  • Request#approve_by: Consolidates the assignment.lms_facade.from_user(...)approve(...) pattern that was duplicated in both the single approve action and the mass-approve helper.

Notable finding: The new_for_student action has no route and is only reachable as a rendered template from new. Left as-is since route changes are out of scope, but worth a follow-up.

Testing

Added 21 new examples covering previously untested paths:

  • export endpoint had zero coverage — added tests for valid token, invalid token, missing token, non-existent course, and status filtering.
  • Staff-only actions: students are now explicitly blocked from approve, reject, and mass_approve.
  • Access control: course-not-found redirect, students blocked when extensions disabled, staff still allowed through.
  • new action: staff renders the on-behalf-of form; users with no course role are redirected.
  • Model specs: Course#extensions_enabled?, Request#pending?, Request.pending, and Request#approve_by.

Full suite went from 479 → 500 examples, 0 failures.

Documentation

No documentation changes required.

Checklist

  • Name of branch corresponds to story

Superconductor Ticket Implementation | App Preview | Guided Review

cycomachead and others added 7 commits July 2, 2026 08:37
Refactored `RequestsController` to improve maintainability and remove
unnecessary indirection. Deleted `RequestService` and moved its logic
into idiomatic controller filters and model methods.

Key changes:
- Removed `RequestService` and folded logic into `before_action` filters.
- Delegated business logic to models, including `Course#extensions_enabled?`
  and `Request#approve_by`.
- Replaced `@role` string comparisons with model-based permission checks
  like `course_staff?` and `course_student?`.
- Added a `pending` scope and `pending?` helper to `Request`.
- Improved test coverage for the `export` endpoint, access control,
  and staff-only actions (+21 examples).

Co-authored-by: Claude Code <noreply@anthropic.com>
- Consolidate staff-only route protection in `require_course_staff`
- Move `new_for_student` to a private method with staff-only rendering
- Implement a top-level enrollment guard in `RequestsController#new`
- Update `Course#extensions_enabled?` to fail closed if settings are nil
- Remove redundant LMS presence checks in request initialization
- Add test coverage for student access to staff-only creation routes

Co-authored-by: Claude Code <noreply@anthropic.com>
…tor-requests-controller/1

Reconcile the RequestsController refactor with main:
- Adopt main's Course#requests_enabled? (drop the branch's duplicate
  extensions_enabled?) and main's argument-free prepare_* helpers.
- Keep the branch's controller rewrite (RequestService removed, model-
  delegated access checks) and the deterministic Course#canvas_id fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Move CSV export logic to Requests::ExportsController to unify before_actions in RequestsController.
- Replace custom authentication and staff checks with shared ApplicationController methods.
- Update `ensure_instructor_role` to use `course_staff?` instead of `@role`.
- Add `require_course_membership` filter to prevent unauthorized access to request actions.
- Narrow LMS check in `new` to specifically verify Canvas integration.

Co-authored-by: Claude Code <noreply@anthropic.com>
The branch's merge of main left three UserToCourse.create! calls in the
requests controller spec; the model was renamed to Enrollment, so these
referenced a constant that no longer exists.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CSV is used by Request.to_csv, not the exports controller (which only calls
it), so the require belongs with the model.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cycomachead
cycomachead merged commit 840d0d1 into main Jul 4, 2026
13 checks passed
@cycomachead
cycomachead deleted the cycomachead/164-refactor-requests-controller/1 branch July 4, 2026 07:46
@cycomachead cycomachead mentioned this pull request Jul 4, 2026
20 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant