Rails 6 introduced a new configuration option implicit_order_value for ApplicationRecord classes. It results in a seemingly buggy behavior of first and last methods before Rails 6 because, by default, they implicitly sort relations by ID values. Unfortunately, it has nothing to do with when it was generated compared to other UUID values from the same table. It means that a single UUID from the table will always have the first place when sorting. PostgreSQL can still sort them using the deterministic algorithm. On the contrary, due to the totally random nature of UUID, it is generated in a non-sequential order. We can safely assume that the most recently created object will have the highest ID value. Integer primary keys are generated sequentially. Let’s take a look at an SQL query generated by running User.last SELECT * FROM users ORDER BY id DESC LIMIT 1 Apparently first and last ActiveRecord::Relation methods no longer worked as expected, returning a seemingly random object from a collection. ![]() UUID order issuesīefore Rails 6, trying out UUID in your app might have been a bit discouraging. ![]() Running this code snippet will not raise an error but rather create a new user object, with id randomly generated by the database. Otherwise, you need to remember to cover these cases.Īnother surprise will happen if you want to create objects with predefined UUID values that might be incorrect: User. It should not affect your logic as long as you use UUIDs only as primary keys, because they cannot be nil. Invalid UUID value is implicitly converted to nil to avoid database level error. It generates the following SQL query: SELECT "users". Consider the following code snippet: User. One surprising feature of ActiveRecord is how it treats invalid UUID values. You need to follow the similar steps of adding a new GUID type column and based on the value from old integer foreign key, you must assign correct UUID keys. I will not go into details on how to migrate associations because it will differ for every use case. class AddUUIDToUsers < ActiveRecord :: Migration def up add_column :users, :uuid, :uuid, default: "gen_random_uuid()", null: false rename_column :users, :id, :integer_id rename_column :users, :uuid, :id execute "ALTER TABLE users drop constraint users_pkey " execute "ALTER TABLE users ADD PRIMARY KEY (id) " # Optionally you remove auto-incremented # default value for integer_id column execute "ALTER TABLE ONLY users ALTER COLUMN integer_id DROP DEFAULT " change_column_null :users, :integer_id, true execute "DROP SEQUENCE IF EXISTS users_id_seq" end def down raise ActiveRecord :: IrreversibleMigration end Then rename the old id column to integer_id, unset it as the primary key in favor of the new uuid column after renaming it to id. You need to start by running a similar migration, that will create a new uuid column. orm :active_record, primary_key_type: :uuid end How to migrate a table from integer to UUID primary key?Ĭhanging the primary key type in the table is not straightforward. If you want all your future models to use UUID for primary keys by default you need to add the following file:Ĭonfig/initializers/generators.rb Rails. timestamps end add_index :comments, :user_id end end Migration creating comments should look like that: class CreateComments < ActiveRecord :: Migration def change create_table :comments, id: :uuid do | t | t. For this sample case:Īpp/models/user.rb class User < ApplicationRecord has_many :comments endĪpp/models/comments.rb class Comment < ApplicationRecord belongs_to :user end Remember to set correct foreign key data type on relation models. You can now configure new tables to use UUID for their primary keys: class CreateUsers < ActiveRecord :: Migration def change create_table :users, id: :uuid do | t | t. To enable UUID in PostgreSQL, you need to create the following migration: class EnableUUID < ActiveRecord :: Migration def change enable_extension 'pgcrypto' end end ![]() Rails makes it just too easy to ship code like: class InvoicesController "b436517a-e294-4211-8312-8576933f2db1" Properly scoping access to resources in web apps with non-trivial business logic is hard.
0 Comments
Leave a Reply. |