Custom Primary Keys in Ruby on Rails
Rails by default assume an application to have an auto-increment index. Not every model requires a primary key that is an auto-increment integer. Since Rails 4, we have the ability to define a custom index.
When we create a migration, we will have to info create_table
that we don't require an ID. Then we need to specify the primary key we intend to use.
In the following example, I require to create a model Country
with a primary key set to code
which is the ISO code of the country.
class CreateCountries < ActiveRecord::Migration[7.0]
def change
create_table :countries, id: false, primary_key: :code do |t|
t.string :code, null: false
t.text :description
# ...
t.timestamps
# You probably would want `code` to be unique. In that case...
t.index :code, unique: true
end
end
end
In addition, we need to specify the Primary Key in the model.
class Country < ApplicationRecord
self.primary_key = :code
end
Now you can create and use the Country
model as if code
is the primary key ID in other models.
Country.find "UK"
# Country Load (0.2ms) SELECT "countries".* FROM "countries" WHERE "countries"."code" = $1 LIMIT $2 [["code", "UK"], ["LIMIT", 1]]
If you miss the primary_key
config in the modal, you may experience errors similar to:
3.0.2 :004 > Country.last.delete
/Users/jdeen/.rvm/gems/ruby-3.0.2/gems/activerecord-7.0.2.3/lib/active_record/relation/query_methods.rb:1524:in `reverse_sql_order': Relation has no current order and table has no primary key to be used as default order (ActiveRecord::IrreversibleOrderError)
It is nice to see people going beyond the default configuration. It is a good sign that something good and interesting is brewing. Happy hacking!
About the Author
Ziyan Junaideen -
Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.