Stage 7 · L30
Apply record scope before pagination and side effects
Core · original Session 7
Authorization scope belongs in the database query before ordering and pagination. list_rentals adds owner_id == actor.id for every non-admin reader, then applies status, stable order and bounds. Admin has a deliberate broader scope. Do not fetch a global page and filter it afterward.
The transfer fixture puts another user's older rental ahead of the caller's own rental. A correct owner-scoped limit1 query returns the caller's record. Post-page filtering would produce an empty result even though the caller has a matching row. The test also confirms admin can see both records under this specific policy.
Single-record reads use the same scope and return404 for a missing or unauthorized record. This masks record existence under the chosen read contract. Action denial such as a customer's check-in is403 because the action is forbidden regardless of a particular record. Decide that distinction consistently; do not leak a title, owner email or count before checking.
Side-effect permission must be decided before a mutation or external call. The router guard rejects unauthorized check-in before the service opens a transaction; the service's direct-call decorator protects that entry too. The fresh-session test verifies the rental stays active. A403 response alone would not establish that an earlier write or audit action was rolled back.
This pattern will also scope provider preparation. A denied rental lookup must not send an outbound request carrying another user's identifier. Protect the preparation query, return plain values, then perform the read-only provider call. Authorization is not an output-field filter.
Follow the running code
Focused lesson example; see the end-of-stage capstone for the cumulative app · stage 07
statement = select(Rental).where(Rental.owner_id == actor.id)
statement = statement.order_by(Rental.created_at, Rental.id).limit(1)
# Apply the caller's ordinary filters before the slice too.Predict and observe this focused example using the concepts explained above. Its boundary is stated in the focused answer.
Guided lab
- Read the explanation and predict the focused example’s outcome.
- Another customer's older row precedes the caller's newer row. Predict the owner-scoped limit1 result and other-record read.
- Compare the observed outcome with the focused answer and state its boundary.
Expected: The query first constrains owner_id, then filters/orders/slices, returning the caller's row. A global slice followed by filtering can return nothing. A single-record read uses the same scope and masks the other record with404; forbidden action is403 and must precede stored/external effects.
- Filtering after pagination loses allowed rows and can expose counts; output redaction cannot undo an unauthorized side effect.
Focused exercise and answer
Complete this focused exercise before reading its answer. The full native transfer is introduced only at the end of the stage.
Your transfer task: Another customer's older row precedes the caller's newer row. Predict the owner-scoped limit1 result and other-record read.
- Another customer's older row precedes the caller's newer row. Predict the owner-scoped limit1 result and other-record read.
Inspect the matching answer
This answer addresses the focused exercise above; the cumulative implementation is shown only after the stage prerequisites.
The query first constrains owner_id, then filters/orders/slices, returning the caller's row. A global slice followed by filtering can return nothing. A single-record read uses the same scope and masks the other record with404; forbidden action is403 and must precede stored/external effects.Check your reasoning
Why does this exercise seed an older other-user row?
Show the explanation
It makes post-page filtering fail observably, proving scope is applied before the page boundary.
Reading progress
54 lessons remain open to guests. Marking a lesson read records reading only; it does not award assessment credit or a certificate.
Device reading marks require browser storage. Reading is always available.
Sign in or create an account to save separate account progress. Your current page is kept.
Your earlier place on this device suggests these lessons. No new lesson is marked read.