Prefer Laravel's expressive, model-aware APIs over manual ID plumbing. Passing models instead of raw IDs is safer (correct key resolution, route model binding) and reads better. Each section shows the pattern to avoid and the one to use.
Pass the model itself to route(), not its key. Laravel resolves thea route key automatically (and respects custom route keys).
// Avoid
route('users.show', $user->id);
// Prefer
route('users.show', $user);Create through the relationship instead of setting the foreign key by hand.
// Avoid
Post::create(['user_id' => $user->id, ...$attributes]);
// Prefer
$user->posts()->create($attributes);attach() and updateExistingPivot() accept models directly.
// Avoid
$user->roles()->attach($role->id);
// Prefer
$user->roles()->attach($role);// Avoid
$user->roles()->where('roles.id', $role->id)->update([...]);
// Prefer
$user->roles()->updateExistingPivot($role, [...]);Use whereBelongsTo() and whereKey() instead of hand-written foreign key or primary key clauses.
// Avoid
Post::where('user_id', $user->id)->get();
// Prefer
Post::whereBelongsTo($user)->get();// Avoid
$user->posts()->where('id', $post->id)->exists();
// Prefer
$user->posts()->whereKey($post)->exists();Use is() (and isNot()) to compare related models instead of comparing IDs.
// Avoid
if ($post->user_id === $user->id) {
// ...
}
// Prefer
if ($post->user()->is($user)) {
// ...
}Use associate() instead of writing the foreign key directly.
// Avoid
$post->update(['user_id' => $user->id]);
// Prefer
$post->user()->associate($user)->save();Use touch() to set a timestamp column to now.
// Avoid
$project->update(['cancelled_at' => now()]);
// Prefer
$project->touch('cancelled_at');Use Gate::allowIf() / Gate::denyIf() for inline authorization checks instead of manual abort(403).
// Avoid
if (! $admin) {
abort(403);
}
// Prefer
Gate::allowIf($admin);
Nice