There are several good reasons for using UUID PK’s but they still byte you in the bottom with occasional WTFs (the default ActiveStorage migration is probably the #1) and it becomes really funny if you have mixed PKs (int, uuid) with active storage …
Can you tell me more about the WTFs you see as the issues here?
The #1 should be a classic not ? When you’ve run your migration with integer as polymorphic reference key, which most users probably do because that’s the default and it often get’s created early stage, you get very confusing behaviour (no errors) when attaching files to your models that have UUIDs as primary keys. most attachments magically disappear while some actually seem to work. RAILS doesn’t give any warning but it could easily check that the the ID types don’t match. This warning would probably save serious amounts of grey hairs
Not wanting to take over this thread, but there was a long discussion on GitHub previously about issues related to UUID primary keys: https://github.com/rails/rails/issues/23422 - it’s currently closed, but it sounds like the issues raised are still a problem in the latest version of Rails.
To summarise the problem I had originally - it was possible to generate a model with a UUID primary key, but when generating further models which referenced that model, the foreign key columns used a bigint
type instead - which broke that relationship pretty effectively.
I realise that it’s the responsibility of the developer to check the migrations are sane, but Rails could save some effort here by inspecting the related table’s primary key type when generating the migration.
Or, just make the type configurable, so we never have to worry about it
This is already configurable! https://blog.bigbinary.com/2016/04/04/rails-5-provides-application-config-to-use-uuid-as-primary-key
I do think that there are discoverability issues for that config option, though. I think there’s merit to the idea of having Rails inspect the PK type when generating the migration.
Is anyone reading this interested in working on that?
Hi @Betsy_Haibel - yes, there’s a config option for using UUID as primary key, but as far as I can remember (since the last time I tried, which has to be well over a year ago), that option still doesn’t affect foreign keys.
Ah, thanks for the correction! You’re totally right. I’d been in a headspace of “why is this not a problem at my work?” (because we use UUIDs, and have a lot of junior and/or new-to-Rails developers.) I’d been hopefully ascribing that to the presence of that default. But I think it might just be that we haven’t created a new table in a long while, and so no one has stubbed their toe on this particular broken stair recently.
it has to do with the sequence of doing things indeed. again, it would already be a major step forward if rails could do a sanity check when the types don’t match.
e.g. scenario resulting in possible grey hair
- start project with some modes that have int’s as PK
- introduce active storage with default active storage migration
- introduce some model with UUID as PK
- give that model an active storage association
- grey hair / no warning
if rails would validate FK type compatibility at load time (no runtime overhead), rails could easily warn the user
@koenhandekyn Did you find any workarounds for working with a mix of UUID and ints in ActiveStorage?
Is it possible to configure active storage to use an alternative FK to the id field for specific models?
Just ran into this issue by chance could have become a much bigger problem had it not been caught now.
you get a long way if you make a migration like this
# typed: true
class ChangeRecordIdToStringForActiveStorageAttachements < ActiveRecord::Migration[6.0]
def up
change_column :active_storage_attachments, :record_id, :string
end
def down
change_column :active_storage_attachments, :record_id, :integer
end
end
Yep…I hit the same snag. We use UUID across the board for PK. Created a new polymorphic relationship (not something I have a lot of experience with), and thought I was good. Got several stories down the road before seeing some SUPER ODD id’s in my child records. No errors, and prior rspec tests did not reveal the problem.
Long story short, I had:
t.references :commentable, polymorphic: true
This produced:
t.string "commentable_type"
t.bigint "commentable_id"
(note the bigint
, where I expected uuid
)
Changing that to:
t.references :commentable, polymorphic: true, type: :uuid
…corrected the problem:
t.string "commentable_type"
t.uuid "commentable_id"