Rails is able to create a table which has composite primary key without a gem.
This is documented in Rails like below:
create_table(:orders, primary_key: [:product_id, :client_id]) do |t|
t.belongs_to :product
t.belongs_to :client
end
ref. Document support for composite primary keys by Nerian · Pull Request #29135 · rails/rails
Create composite primary key
Let’s create a table having composite primary key step by step.
First, generate migration file which has two types of id
columns.
$ rails generate migration createRelationship follower_id:bigint followed_id:bigint
invoke active_record
create db/migrate/20190905xxxxxx_create_relationship.rb
The created file is like this:
# db/migrate/20190905xxxxxx_create_relationship.rb
class CreateRelationship < ActiveRecord::Migration[5.2]
def change
create_table :relationships do |t|
t.bigint :follower_id
t.bigint :followed_id
end
end
end
What we’d like to do is creating a composite primary key of follower_id
and followed_id
.
So, add primary_key
option and pass Array of composite primary key as a value.
# db/migrate/20190905xxxxxx_create_relationship.rb
class CreateRelationship < ActiveRecord::Migration[5.2]
def change
create_table :relationships, primary_key: [:follower_id, :followed_id] do |t|
t.bigint :follower_id
t.bigint :followed_id
end
end
end
After running rails db:migrate
, you can see composite primary key in the table. This is a created schema on my local MySQL.
mysql> desc relationships;
+-------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------+------+-----+---------+-------+
| follower_id | bigint(20) | NO | PRI | NULL | |
| followed_id | bigint(20) | NO | PRI | NULL | |
+-------------+------------+------+-----+---------+-------+
This is composite primary key, so:
- You can’t insert
null
- You can’t insert same record
insert relationships values (null, null);
ERROR 1048 (23000): Column 'follower_id' cannot be null
mysql> insert relationships values (1, 1);
Query OK, 1 row affected (0.01 sec)
mysql> insert relationships values (1, 1);
ERROR 1062 (23000): Duplicate entry '1-1' for key 'PRIMARY'
Heads-up
ActiveRecord can’t find composite primary key record since it does not support.
irb> Relationship.find(1)
WARNING: Active Record does not support composite primary key.
relationships has composite primary key. Composite primary key is ignored.
Traceback (most recent call last):
1: from (irb):2
ActiveRecord::UnknownPrimaryKey (Unknown primary key for table relationships in model Relationship.)
If you want to get composite primary key support, use composite_primary_keys gem.