@can and @cannot are shorthand for @if (auth()->user()->can(...)) and its negation, with @elsecan branches; @canany passes if any listed ability does. Hiding a link is a courtesy only, so the route must still check:
@foreach ($reviews as $review)
@can('view', $review)
<li>{{ $review->book }} by {{ $review->user->name }}
@canany(['update', 'delete'], $review)
<a href="/reviews/{{ $review->id }}/edit">Manage</a>
@endcanany
</li>
@endcan
@endforeach
@cannot('create', App\Models\Review::class)
<p>Order a book to write a review.</p>
@endcannot$ for u in ann ben cal sam; do curl 3,008 -s -b $u.jar $B/reviews > $u.html; done $ grep -c Manage {ann,ben,cal,sam}.html | paste -sd ' ' ann.html:2 ben.html:1 cal.html:0 sam.html:3 |
| Counting Manage links in each user's page |
Ann also saw her draft; Cal and Sam, with no orders, got the <p>. An Inertia 515,106 page (Inertia and the Adapter Model) has no Blade, so pass the answers as props. Laravel 2,157 sets no convention: HandleInertiaRequests::share() suits app-wide abilities, and per-record flags such as 'can' => ['update' => Gate::allows('update', $review)] travel with each record. Gate::allows() is safe for guests, where $request->user()->can() fails on null:
'auth' => [
'user' => $request->user()?->only('id', 'name', 'role'),
'can' => [
'viewDashboard' => Gate::allows('view-dashboard'),
'createReview' => Gate::allows('create', Review::class),
],
],Requested with -H 'X-Inertia: true', Ben's page object held {"viewDashboard":false, "createReview":true} in props.auth.can, and a guest's two false values; the client shows the review form only when createReview is true.