Ruby on Rails (RoR) likes to emphasise the concept of convention over configuration. Therefore, it seeks to minimialise the amount of configuration
by resorting to some defaults. These defaults are sometimes not desirable, and RoR does not always make it easy to deviate from these defaults.
By default, all the models in RoR has a column called id of the type :primary_key. The various database adapters that RoR uses to talk to the databases will translate the type to the appropriate column type that the database supports. For example, in PostgreSQL, this would be serial primary key.
There are often times when you would like to change the primary key of tables to be of a different type (such as when you are using some generated UDID as
the primary key), or you simply want to use multiple columns as the primary key. The latter problem can be solved by using
a Ruby Gem but the former is not so easily solved.
Stackoverflow provides a solution to change the type of the primary key, but it is lacking in
some ways. Primarily, the schema file generated by Rails will now omit the necessary SQL instructions to actually make the custom primary key
column a primary key in the database.
The first step to changing the primary key involves the migration file.
The span used is similar whether you are changing an existing table or if you are creating a new table.
A migration file might look like this:
If you are creating a new table, your migration might look like this:
Notice the id: false options you pass into the table — this asks Rails not to create a primary key column on your behalf.
In the model, it is essential that you add the following line in order for
Rails to programmatically find the column you intend to use as your primary key.
You might now notice that the db/schema.rb file generated by Rails will
look like this:
When you invoke rake db:schema:load to set up a new machine, the table
you create will lack a primary column constraint. This is because the custom
execute query you added to the migration will never get run, and Rails does
not know what goes on in those execute statement.
A hacky solution we came up with was to add a rake task to be run after
rake db:schema:load is run.
In your lib/tasks directory, add a file like after_db_schema_load.rake:
Whenever you run rake db:schema:load, the primary key constraint will now
be set accordingly.