php 103 lines · 4 tabs

Authorizing Article Edits with a Laravel Policy in Controller and Blade

Shared by codesnips Sep 2026
4 tabs
<?php

namespace App\Policies;

use App\Models\Article;
use App\Models\User;

class ArticlePolicy
{
    public function before(User $user, string $ability)
    {
        if ($user->is_admin) {
            return true;
        }

        return null;
    }

    public function update(User $user, Article $article): bool
    {
        return $user->id === $article->user_id
            || $user->hasRole('editor');
    }

    public function delete(User $user, Article $article): bool
    {
        return $user->id === $article->user_id;
    }
}
4 files · php Explain with highlit

This snippet shows the canonical Laravel way to answer a single question — may this user edit this article? — once, in a Policy, and then reuse that answer everywhere. Centralizing authorization logic in a policy class avoids the classic bug where the controller allows an action the view hides, or vice versa: both derive their decision from the same method.

The ArticlePolicy file defines per-action methods (update, delete) that receive the authenticated User and the Article instance. Each returns a boolean, and Laravel's authorization layer treats truthy as allow. The update method permits either the article's author ($article->user_id === $user->id) or anyone with an editor role, which demonstrates how business rules live in one place. The before hook is a common escape hatch: returning true for admins short-circuits every ability so admins never get blocked; note that it returns null (not false) for non-admins so the specific methods still run — returning false there would deny everyone.

The AuthServiceProvider file wires the model to its policy in the $policies map so Gate and helpers like $user->can() resolve automatically. This registration is what lets the framework infer the right policy from the model class alone.

In ArticleController, the edit and update actions call $this->authorize('update', $article). That helper throws an AuthorizationException (rendered as a 403) when the policy denies, so no unauthorized write reaches the database. The edit action also loads the form; because authorization runs first, a tampered URL cannot open the editor for someone else's article. Route-model binding supplies the $article, keeping the controller thin.

Finally, articles/show.blade.php uses the @can('update', $article) directive to render the Edit button only when the same policy permits it. This is purely cosmetic hardening — the server-side authorize call is the real gate — but it produces a coherent UI. The key takeaway is layering: policy defines the rule, controller enforces it, and Blade reflects it, all from one source of truth. A pitfall to avoid is enforcing only in Blade; hidden buttons are not security.


Related snips

ruby
payload = {
  sub: user.id,
  iss: 'https://auth.example.com',
  aud: 'codesnips-api',
  exp: 15.minutes.from_now.to_i,
  iat: Time.now.to_i,

JWT issuance and verification without common footguns

jwt authentication api
by Kai Nakamura 2 tabs
ruby
class SignupForm
  include ActiveModel::Model
  include ActiveModel::Attributes

  attribute :account_name, :string
  attribute :email, :string

Shallow Controller, Deep Params: Form Object Pattern

rails activemodel form-object
by codesnips 3 tabs
javascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["form"]
  static values = { delay: { type: Number, default: 250 } }

Debounced live search with Stimulus + Turbo Streams

rails hotwire stimulus
by codesnips 4 tabs
bash
#!/usr/bin/env bash
set -euo pipefail

export VAULT_ADDR="https://vault.internal:8200"
export VAULT_TOKEN="${VAULT_TOKEN:?missing VAULT_TOKEN}"

Secrets management with environment isolation and Vault

secrets-management vault environment-variables
by Kai Nakamura 1 tab
php
<?php

namespace App\Providers;

use App\Contracts\PaymentGateway;
use App\Services\StripePaymentGateway;

Laravel service container and dependency injection

laravel dependency-injection service-container
by Carlos Mendez 2 tabs
typescript
import { randomBytes, createHash } from "crypto";
import jwt from "jsonwebtoken";
import { RefreshTokenStore } from "./store";

const ACCESS_SECRET = process.env.ACCESS_SECRET!;
const ACCESS_TTL = "15m";

JWT access + refresh token rotation (conceptual)

security node jwt
by codesnips 3 tabs

Share this code

Here's the card — post it anywhere.

Authorizing Article Edits with a Laravel Policy in Controller and Blade — share card
Link copied