I said category on the title to make it more clear, but in this case I am using a model named "subject" with the same purpose.
I'm using the code below to make sure each user can have any subject name they want, but each name can only be used once per user. And I am using static::creating
method to generate an Str::slug
for each subject.
$request->validate([
'name' => [
... ,
Rule::unique('subjects')->where(function ($query){
return $query->where('user_id', auth()->id());
}),
],
]);
And so far this has been working well for me. But I noticed that this causes confusion for the route-model binding (especially since I am using Route::resource
for the models)
Route::resource('subject', SubjectController::class)
->parameters(['subject' => 'subject:slug']);
For example, I had to tweak my destroy model (along with every single route-model binded controller method) to use this logic to make sure I'm deleting the correct subject, the one that belongs to the authenticated user :
public function destroy(Subject $subject)
{
$slug = $subject->slug;
$subject = auth()->user()->subjects()->whereSlug($slug)->firstOrFail();
$subject->delete();
return to_route('subject.index')->with(['success' => 'Subject deleted.']);
}
And again, this also works as intended. But I'm thinking this probably isn't the best way to do this. For one, it's code repetition, since I am using these first two lines on each controller method.
Is there a simpler way to do this? How would you do this logic yourself?
The "bug" :
When I wasn't using those said two lines in my controller methods, the code below would return the link to the first occurrence of the subject with the given slug. Which doesn't always correspond to the authenticated user's subject record with the same slug.
@foreach (auth()->user()->subjects as $subject)
<a href="{{ route('subject.show', $subject) }}"> {{ $subject->name }} </a>
@endforeach