We've moved discussions to Discord

UUID for database records

Nick Willever
Any reason I couldn't implement UUID for database records for Jumpstart? (other than the obvious can't easily pull in new commits and should do this at the beginning of a project)

Thinking I just need to enable these extensions and then add a migration to convert.

enable_extension 'pgcrypto'
enable_extension 'plpgsql'
enable_extension 'uuid-ossp'

Rails.application.config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid
end
Chris Oliver
Don't see any reason why you couldn't.
Nick Willever
Thanks Chris, I'll report back once I try it.

Also thanks for the great product! Been using rails since 2.4 and this greatly helps push a web app to be quickly usable.
Chris Oliver
Glad to hear it! Need to add you as a testimonial or something. 😜
Nick Willever
It didn't take too long, I ended up rewriting the migrations, instead of doing a conversion with a migration. Administrate's fields needed to be updated from Number to String.

All tests were passing before and they are all passing after.
Scott Wright
Can you go into a bit of detail on the changes to Administrate's fields (Which migrations, which exact fields)?



In one of my project I tried to use UUID as the primary key and things worked until I needed ActiveStorage. Based on my research at that time ActiveStorage can't work with UUID. I am not sure if that situation changed
Nick Willever
  the administrate's fields called for an Integer, had to change that to String. This is in the dashboard files,  in the ATTRIBUTE_TYPES array - id: Field::String - make sure to change any other ID fields too.

The migrations I changed:
Added the id: :uuid into all create_table's: create_table :<table name>, id: :uuid do |t|
Any belongs_to or references I added type: :uuid - t.references :blob, type: :uuid
Also added timestamps to each table, then added an index on created_at: t.index :created_at

Also, these links should help:
- https://www.kostolansky.sk/posts/how-to-migrate-to-uuid/
- https://pawelurbanek.com/uuid-order-rails
Nick Willever
- as long as you update active storage's references from IDs to UUID it works.

    create_table :active_storage_blobs, id: :uuid do |t|
      t.string   :key,        null: false
      t.string   :filename,   null: false
      t.string   :content_type
      t.text     :metadata
      t.bigint   :byte_size,  null: false
      t.string   :checksum,   null: false
      t.datetime :created_at, null: false

      t.index [ :key ], unique: true
      t.index :created_at
    end

    create_table :active_storage_attachments, id: :uuid do |t|
      t.string     :name,     null: false
      t.references :record, type: :uuid,   null: false, polymorphic: true, index: false
      t.references :blob, type: :uuid,     null: false

      t.datetime :created_at, null: false

      t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
      t.index :created_at
    end



Scott Wright
Thank you Nick Willever!
I had all the UUIDs working. I too just altered the migrations and rebuilt from scratch in a brand new DB. The administrate stuff helps a lot.

I have some integration tests failing. They seem to be failing because of mocks and fixtures. You mentioned that all your tests are passing, did you delete the integration tests previously?

One thing that I already fixed, is setting an implicit order column. This article speaks to that. You are obviously doing that as well (witness your indexes on created_at) but I don't think you explicitly mentioned it here. I added the statement to application_record.rb under app/models. If I come across a table where I don't want a uuid for a key and I want to use the standard integer, I will explicitly set implicit_order_column to id in the model, which is the Rails default, if not explicitly set on a model (or abstract class that models inherit from). Along with this change, I modified some of the fixtures to specify a created_at time so that the fixture order remains the same as it would have been with integer ids.
  created_at: <%= Time.current - 5.minutes %>
That was for the first user in users.yml and I did - 4minutes for the 2nd and so on.

I am working on a couple of other integration test failures having to do with subscriptions and teams. When I get those resolved I will post here.
Ken Lynch
 , did you ever get the other integrations tests to pass?
Eugene Cook
Would really love to see UUIDs added as a default option.
Eugene Cook
In case anyone is interested, here is a diff patch of all the changes that need to be made. This includes creating the tables with UUID keys, as well as changing the references and belongs_to to UUID. Furthermore, implicit_order_column has been set to created_at for the relevant tables. I was banging my head wondering why tests were sometimes failing, especially when running the whole test suite, and after some testing realized it was because .last was pulling the wrong record.

 

P.S. One more note: it looks like the [4.2] migration uses uuid_generate_v4 by default, which is why I set it manually to use gen_random_uuid, so you wouldn't have to enable uuid-ossp just to support a legacy migration.
Nick Willever
Any reason I couldn't implement UUID for database records for Jumpstart? (other than the obvious can't easily pull in new commits and should do this at the beginning of a project)

Thinking I just need to enable these extensions and then add a migration to convert.

enable_extension 'pgcrypto'
enable_extension 'plpgsql'
enable_extension 'uuid-ossp'

Rails.application.config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid
end
Chris Oliver
Don't see any reason why you couldn't.
Nick Willever
Thanks Chris, I'll report back once I try it.

Also thanks for the great product! Been using rails since 2.4 and this greatly helps push a web app to be quickly usable.
Chris Oliver
Glad to hear it! Need to add you as a testimonial or something. 😜
Nick Willever
It didn't take too long, I ended up rewriting the migrations, instead of doing a conversion with a migration. Administrate's fields needed to be updated from Number to String.

All tests were passing before and they are all passing after.
Scott Wright
Can you go into a bit of detail on the changes to Administrate's fields (Which migrations, which exact fields)?



In one of my project I tried to use UUID as the primary key and things worked until I needed ActiveStorage. Based on my research at that time ActiveStorage can't work with UUID. I am not sure if that situation changed
Nick Willever
  the administrate's fields called for an Integer, had to change that to String. This is in the dashboard files,  in the ATTRIBUTE_TYPES array - id: Field::String - make sure to change any other ID fields too.

The migrations I changed:
Added the id: :uuid into all create_table's: create_table :<table name>, id: :uuid do |t|
Any belongs_to or references I added type: :uuid - t.references :blob, type: :uuid
Also added timestamps to each table, then added an index on created_at: t.index :created_at

Also, these links should help:
- https://www.kostolansky.sk/posts/how-to-migrate-to-uuid/
- https://pawelurbanek.com/uuid-order-rails
Nick Willever
- as long as you update active storage's references from IDs to UUID it works.

    create_table :active_storage_blobs, id: :uuid do |t|
      t.string   :key,        null: false
      t.string   :filename,   null: false
      t.string   :content_type
      t.text     :metadata
      t.bigint   :byte_size,  null: false
      t.string   :checksum,   null: false
      t.datetime :created_at, null: false

      t.index [ :key ], unique: true
      t.index :created_at
    end

    create_table :active_storage_attachments, id: :uuid do |t|
      t.string     :name,     null: false
      t.references :record, type: :uuid,   null: false, polymorphic: true, index: false
      t.references :blob, type: :uuid,     null: false

      t.datetime :created_at, null: false

      t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
      t.index :created_at
    end



Scott Wright
Thank you Nick Willever!
I had all the UUIDs working. I too just altered the migrations and rebuilt from scratch in a brand new DB. The administrate stuff helps a lot.

I have some integration tests failing. They seem to be failing because of mocks and fixtures. You mentioned that all your tests are passing, did you delete the integration tests previously?

One thing that I already fixed, is setting an implicit order column. This article speaks to that. You are obviously doing that as well (witness your indexes on created_at) but I don't think you explicitly mentioned it here. I added the statement to application_record.rb under app/models. If I come across a table where I don't want a uuid for a key and I want to use the standard integer, I will explicitly set implicit_order_column to id in the model, which is the Rails default, if not explicitly set on a model (or abstract class that models inherit from). Along with this change, I modified some of the fixtures to specify a created_at time so that the fixture order remains the same as it would have been with integer ids.
  created_at: <%= Time.current - 5.minutes %>
That was for the first user in users.yml and I did - 4minutes for the 2nd and so on.

I am working on a couple of other integration test failures having to do with subscriptions and teams. When I get those resolved I will post here.
Ken Lynch
 , did you ever get the other integrations tests to pass?
Eugene Cook
Would really love to see UUIDs added as a default option.
Eugene Cook
In case anyone is interested, here is a diff patch of all the changes that need to be made. This includes creating the tables with UUID keys, as well as changing the references and belongs_to to UUID. Furthermore, implicit_order_column has been set to created_at for the relevant tables. I was banging my head wondering why tests were sometimes failing, especially when running the whole test suite, and after some testing realized it was because .last was pulling the wrong record.

 

P.S. One more note: it looks like the [4.2] migration uses uuid_generate_v4 by default, which is why I set it manually to use gen_random_uuid, so you wouldn't have to enable uuid-ossp just to support a legacy migration.
Notifications
You’re not receiving notifications from this thread.
© 2022 Jumpstart Pro by GoRails, LLC