I'm trying to rename the default id column to uuid, but I'm getting a Field 'uuid' doesn't have a default value when inserting into that model, the eloquent model does make use of HasUuids and uniqueIds which returns an array: ['uuid'] but that still doesn't solve it, does laravel expect the primary key to always be id to properly generate uuids for those columns as default? or is there a way to override that? thanks!
#custom named uuid primary key
167 messages · Page 1 of 1 (latest)
You'd still need to override the models PK property if you aren't using ID as the column name.
public $primaryKey = 'uuid';
and set $increments = false
oh right; I did that now however it seems to still throw Field 'uuid' doesn't have a default value
Trait does that automatically if PK in array of columns for uuid.
protected $primaryKey = 'uuid';
public $incrementing = false;
protected $keyType = 'string';
did that and it still threw the error
okie doke
Can you show the entire model?
And when you create the model, you aren't muting events are you? Common in feature tests
class User extends Authenticatable
{
use HasUuids, MustVerifyEmail, HasApiTokens, HasFactory, Notifiable;
protected $primaryKey = 'uuid';
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
Schema::create('users', function (Blueprint $table) {
$table->uuid('uuid')->primary();
$table->string('name', 50);
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
note that I removed the incrementing and keytype since you mentioned the trait handles that, I had it before this
havent muted anything yet no, just creating a user in a seeder
What about the uniqueIds() method? You still have that on your model right?
yeah had that too, but removed it to test right as you asked me, let me add it back
I'm trying to rename the default
idcolumn touuid
I’d strongly recommend keeping the default primary key columns, and just adding a seconduuidcolumn to your models.
any reason why I cant just use uuids as primary
Was going to be my closing argument XD
You can, but it’s far better and more performant to use integers as primary keys and foreign keys. They’re integers by default for a reason.
the docs hinted at this being possible so I'm confused whats missing
makes sense, but now I'm in for the butter, and would love to know why this doesnt work
It's just against the pattern/framework and will often cause issues. However in general, it's common to use ID int internally and expose uuids over the wire, like api
went through at least 500 pages to make sure I didnt miss something 😄
No one has said it “doesn’t work”.
the error did 😛 not saying any of you did
It’s just better to use integers over UUIDs for your primary and foreign keys.
noted and will switch to that of course, but still want to know why this doesnt work even though primary key is set now too 😄
The error though I'm unsure. If you define the primary Key property, and you return uuid in the method of columns, you should be golden afaik
some kind of cache I should bust maybe?
Usually not with models
HasUuids does that trait define anything that might be overriding the one you've set?
is there anything else that could be missing, like uuid as fillable so laravel can do its default uuid generation?...
how do I check?
removing it at least still throws the error
The trait adds a model::creating listener that should fill out the column, if it's not working, chances are something's misconfigured
if I use uniqueIds am I forced to override the uuid method maybe?
Tbf the docs don't say that you have to define any of those properties above
even if I add it, it still fails anyway meh
It’d probably be easier if you just showed us what your model and migration looks like currently.
so adding the trait expects you to have 'id' as the primary key still
there, just with the:
public function uniqueIds(): array
{
return ['uuid'];
}
also present
howd u check and is there a way to override that?
remove all else incl fillable etc?
no remove public $incrementing = false;
protected $keyType = 'string';
if they're still in there
I just realized....could fillable stop uuid from being filled? I have all my models unguarded.
It might be that this use case just isn't accounted for - a custom PK name AND UUIDs
You didn't put uuid in fillable
Hmm
class User extends Authenticatable
{
use HasUuids;
protected $primaryKey = 'uuid';
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function uniqueIds(): array
{
return ['uuid'];
}
}
that still throws
uuid in fillable doesnt work either
Which bit of code is throwing the error btw? you running migrations / seeder / hitting a URL or something else?
seeder
does it give you a stack trace?
i.e. does it tell you which line of the seeder is causing it?
all the seeder does:
DB::table('users')->insert([
'name' => "test",
'email' => Str::random(6) . "@gmail.com",
'email_verified_at' => now(),
'password' => Hash::make('password'),
]);
🤔
You're not using factories
No wonder
There's no model events to be fired to trigger uuid to be made
You're inserting directly
User::factory()->create()
You made your model factories right?
does laravel not generate that during creation?
Your model already has the factory trait
Not unless you tell it to with the f flag
php artisan make:model User -fm
oh there is already a userfactory
I think the seeding example is what had this direct insertion example
let me check to make sure
General seeding will show both I think
But 99% of the time you should be using factories IMO
More so when you rely on eloquent events to trigger things
Scroll down
To the user factory
Of course, manually specifying the attributes for each model seed is cumbersome.
I didnt think it's cumbersome 😛 so didnt read further
Just wait till you have 30 models to seed and feature tests to run
but it seems it's what makes eloquent be able to hook into the process
Yes, uuids relies on the eloquent creating event to intercept and set the keys
I wonder, was there any path in the docs I could have taken that would've explained I need factories to avoid this uuid issue?
I think I went through all of them earier
Inserting raw data with the DB facade doesn't trigger anything with eloquent
Not sure a direct path. Uuids is more "advanced" in that it sort of assumes you know how that works (relying on eloquent events)
Before L9 had that trait, devs had to manually make their own and hook I to the creating event in the models boot
I'd follow more the eloquent docs though
Not the pure DB ones initially
I think I was just uuid generating on insertion in the old laravel versions yeah
no event/hooks/..
all examples back then also just implied that anyway
Glad as soon as you showed how you're seeding, the answer screamed out lol. Did you get it workig now?
ahhhhhhh there we go
You mean other than continuing to read after, “Of course, manually specifying the attributes for each model seed is cumbersome”?
but that just explains the factories themselves not that uuids require that because of some kind of eventing
I dont think hasuuids is even explained in the docs
about to try, was curious about picking apart the factories 😛
Because it's off the traveled path so to speak
I also took note to change it to id+uuid instead of uuid only, since it does make sense that it'd be faster
but for now I want to see it working 😄
Like many engineering manuals, they hold your hand initially, but it becomes more cryptic as you dive deeper, as it assumes you've encountered and understood some of what they imply.
the hasPosts looks interesting too because the default userfactory never defined that
The issue here was, you added behaviour to a model, and then you didn’t use the model.
More magic methods. I'd reccomend staying away from them until you also understand what they do. And even then, I'd stay far from them. Magic methods don't make it easy on your IDE/static analyzer.
so is "posts" the literal posts, e.g. blogposts or does that refer to some actual magic
That assumes you have a posts() method on your model for a hasMany relation
It's hideous
interesting, something to explore just in case in the future I suppose, but not now 😛
neat I think the user one worked, let me check database
haha yep it did, now to convert it over to id and uuid, incl. the other ones 😄
you guys are awesome, thanks!
👍
interesting, so if I was going to use this later hypothetically speaking; I'd have to each time use this: https://laravel.com/docs/10.x/eloquent-factories#overriding-attributes so that uuids are propagated through to the uuid column I assume?
Huh? You never need to overwrite the uuid. It's made each time for you, and as the name suggest, it's universally unique.
But if you want to set custom names instead of letting faker make them from your model factory definition for example, then sure.
nah I meant if I want to insert into that model, I'd need to use the factory so that it generates the uuid, and for that it seems I'd need to override the attributes definition() has
right? 😄
No. Definitions are default values. You don't define the uuid in your definition because it is made for you when you run create.
Don't use make() unless you have a reason and also understand make doesn't fire creating event, thus no uuid will be set
It sounds like you need to get comfortable with Laravel and how it works before you start overriding and changing defaults.
it was way simpler last time I touched it, please be fair.. 😄
Still as simple, just more options
yes I'm not saying anything about the uuid field itself, I'm just making a hypothetical example where I'd not switch over to id+uuid and keep uuid as my primary key
so then if I want to insert e.g. name,password,.. and have laravel generate the uuid for me, I'd need to use ->make() with overrides?
just trying to wrap my head around how this would work in theory
Pass array of attributes to create method
Don't use make. That's no different than newing up a model inline, setting attributes manually, and not persisting to db.
$user = User::factory()->create([
'name' => 'Abigail',
]);
ahh I see
Yea
oh I thought the earlier seeder made use of ->make too, but that was create
make is simply to init those
Yea, which is fine and all (I have reasons to do so) but you must be aware that when you rely on eloquent events, making will not trigger those nor your model observers.
I guess it makes sense it wouldnt, because otherwise youd fire events that didnt actually create a row?
or is there another reason
Well yea, but in general, model events are fired when dealing with an actual DB life cycle through the model. Make is none of those.
Read these
👍
I see some of the other models have hasfactory but laravel didnt generate a factory for them
the models being ones I created with artisan
is this expected behavior?
As I showed earlier, you must use the -f flag when you make a model to also make factory
I always use -fm
To make model with factory and migration
Yes. Easier to remove two lines in the rare case you don't want a factory
true 😄
I use -mf to give myself a smile during the day. Even better if you want a seeder: -mfs
Damn, I forgot that joke.
Lmao
“Model, motherf—ers!”
again, you guys are truly amazing! 💖