I'm attempting to build a simple many-to-many relationship in Laravel 8 but I'm running into an odd problem. I'm building the fairly standard User/Roles relationship but with one difference: my primary key on those two tables is a UUID rather than an integer.
There aren't any errors but when I attach a role to a user with $user->roles()->attach($userRole);
the data saved in the role_user
linking table is missing the user_id
, the role_id
is inserted correctly. I originally had a problem where the role_id
wasn't saving either but I worked out that was down to specifying protected $keyType = 'string';
on the models.
What I can't work out is if this is being caused by me using UUID's or I've done something else fundamentally wrong.
User Model
class User extends Authenticatable
{
use HasFactory, Notifiable;
protected $primaryKey = 'id';
protected $keyType = 'string';
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
protected static function boot()
{
parent::boot();
self::creating(function ($model) {
$model->id = (string)Str::uuid();
});
}
public function roles()
{
return $this->belongsToMany('App\Models\Role')
->using('App\Models\RoleUser');
}
}
RoleUser Model
class RoleUser extends Pivot
{
use HasFactory;
protected $primaryKey = 'id';
protected $keyType = 'string';
protected static function boot()
{
parent::boot();
self::creating(function ($model) {
$model->id = (string)Str::uuid();
});
}
}
What I end up with, in the DB is the following.
User / Role assignment code
$adminRole = Role::where('name', 'admin')->first();
$userRole = Role::where('name', 'user')->first();
$admin = User::create(['name' => 'Admin User', 'email' => '[email protected]', 'password' => Hash::make('adminpass')]);
$admin->save();
$user = User::create(['name' => 'User User', 'email' => '[email protected]', 'password' => Hash::make('userpass')]);
$user->save();
$admin->roles()->attach($adminRole);
$user->roles()->attach($userRole);
$user->save();
$admin->save();
I'm really lost here, possibly because I'm new to Laravel.
So if anybody else runs into the above issue the solution I found was to:
When building the table in the migration make sure to set the uuid as primary! $table->uuid('id')->primary();
And the models should all be setup as follows:
protected $primaryKey = 'id';
protected $keyType = 'string';
public $incrementing = false;
That above combination seems to have resolved my issue. It seemed to be building the User model but not assigning it's UUID (despite it being saved in the database). If I were to simply reload the model using $user = User::where('email', '=', '[email protected]');
it would then work perfectly fine as the model picked up the ID.
Hopefully this helps somebody else out in the future!