Use Eloquent Relationships to Write Cleaner Code
Relationships are not only for reading data. Creating records through them removes hand-wired foreign keys and a whole class of bugs.

Eloquent relationships are usually introduced as a way to read related data: $post->comments,
$user->orders. They are just as useful for writing it. Creating records through a relationship
removes a whole class of boilerplate and a whole class of bugs.
Wiring foreign keys by hand
$article = new Article;
$article->title = $request->input('title');
$article->content = $request->input('content');
$article->verified = $request->boolean('verified');
$article->category_id = $category->id;
$article->save();
Six lines to create one record, and one of them is the most error-prone line in the snippet:
category_id = $category->id. Forget it and you get an orphaned article or a database error. Copy it
into another place with the wrong variable and you get an article in the wrong category, silently.
Let the relationship set the key
$category->articles()->create(
$request->safe()->only(['title', 'content', 'verified'])
);
$category->articles() already knows that the foreign key is category_id and that its value is
$category->id. Calling create() on the relationship fills it in for you. safe()->only() takes
the validated input from the Form Request and passes through only the fields you name.
The same pattern covers the other relationship types:
$user->posts()->create($data); // hasMany
$post->tags()->attach($tagIds); // belongsToMany
$post->tags()->sync($tagIds); // replace the full set
$comment->author()->associate($user); // belongsTo
Why this pays off
Foreign keys are handled once. The relationship definition on the model is the single source of truth for how two tables connect. Nobody has to remember the column name at the call site.
The code says what it means. $category->articles()->create(...) reads as "create an article in
this category". Six property assignments read as "set some fields", and you have to work out the
intent yourself.
Scoping comes for free. Relationships compose with scopes and constraints.
$user->posts()->published()->latest()->get() cannot accidentally return another user's posts,
because the relationship always adds the user_id condition.
Safer authorization. Creating through $request->user()->posts() guarantees the post belongs to
the authenticated user. Setting user_id from the request is how people end up writing posts on
behalf of someone else.
Where to be careful
create() uses mass assignment, so the fields you pass must be listed in the model's fillable
attributes. That is a feature: it forces you to decide which fields may be set from input. Combined
with safe()->only(), it gives you two layers of protection against unexpected columns.
Relationships also make it easy to trigger queries without noticing. Accessing $article->category
inside a loop runs one query per article. When you read through relationships in a list, eager load
them with with() up front.
A useful rule of thumb:
- Creating a child record → create it through the parent's relationship.
- Linking many-to-many →
attach(),detach()orsync(), never manual pivot inserts. - Reading related data in a loop → eager load with
with()first.
The practical test
Search your codebase for _id = $. Every hit is a foreign key being assigned by hand. Most of them can
become a single call through a relationship, and each one you convert is one less place where the
wrong ID can slip in.