Let's see how to work with uuids in Rails. First of all, have in mind this is
not the default in Rails, but it should be fine/easy to implement.
Use it in both sides
We needed to use UUIDs in one of our projects. Our front-end application was
generating UUIDs and we wanted to use it also in our back-end.
Using UUIDs helps us not having a centralized id generation. We don't need to
rely on just one place to create resources.
Imagine you have this scenario: a react application creating and editing
resources and a Rails API. The React Application communicates with the back-end. It needs to have local IDs before persisting data, in order to reference relationships ahead of time, and it creates a large graph of objects at once.
Should you have different IDs for both sides? No, you don't need that. You can
generate UUIDs in JavaScript and use them for both sides.
On Rails
Enable the extension pgcrypto.
Previously the extension you needed was uuid-ossp.
So, depending in which Postgres version you're using, you can create a migration
to enable this extension. In our case, we will enable both.
rails migration EnableUuidExtension
And our migration will look like:
class EnableUuidExtension < ActiveRecord::Migration[5.1]
def change
enable_extension 'uuid-ossp'
enable_extension 'pgcrypto'
end
end
The next thing is to use the uuid in one of our models. We can do that in two ways:
1.Using id: false
class CreatePerson < ActiveRecord::Migration[5.1]
def change
create_table :people, id: false do |t|
t.uuid :id, null: false
t.string :name
t.timestamps
end
add_index :people, :id, unique: true
end
end
In this case, we are using id:false in our create_table and we are setting the
id as uuid. We are also creating the index here for our id and setting the id to not be null. In order to create the uuid, you could create a before_create and every time it creates a new object you could set the uuid.
2.Using id: uuid
class CreatePeople < ActiveRecord::Migration[5.1]
def change
create_table :people, id: :uuid do |t|
t.string :name
t.timestamps
end
end
end
In this case, we are passing id: :uuid in the create_table and we don't need
to pass the id inside of the block. Doing that, it generates a uuid every time
you create a new object. This should be a normal way to use uuids.
If we try to create a new person, you can see it generates a new uuid for that:
irb(main):002:0> p = Person.create
(0.2ms) BEGIN
SQL (2.2ms) INSERT INTO "people" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2017-07-14 03:06:32.697148"], ["updated_at", "2017-07-14 03:06:32.697148"]]
(1.9ms) COMMIT
=> #<Confirmation id: "886bb121-bd76-4199-9dcb-ce40e0164edf", name: nil, created_at: "2017-07-14 03:06:32", updated_at: "2017-07-14 03:06:32">
Checking
Now, imagine you have set up uuids in your Rails application, and you want to
use it.
And you try to create a new Person and you pass a uuid 123:
irb(main):001:0> p = Person.new(id: '123')
=> #<Person id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):002:0> p.id
=> nil
Doing that, you can see the person didn't get the id. Why did this happen?
This is because ActiveRecord
checks
if the id matches the regular expression. As we are using uuids, it should be a
real uuid and not 123. Thanks Rafael Sales to point me out this!
Right now, if we try to pass a uuid to our object, it should work.
irb(main):002:0> p.id
=> nil
irb(main):003:0> p.id = SecureRandom.uuid
=> "e3e0f7c2-8a85-42b9-a31d-867504cb6eb5"
irb(main):004:0> p.id
=> "e3e0f7c2-8a85-42b9-a31d-867504cb6eb5"
I hope this post helps you see how simple it is to use uuids in Rails.
Interesting Links