Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add composite primary keys in db using Rails?

I'm using Rails 5.0 with Postgresql 9.5

I'm in need to add composite primary keys to my model 'User_achievement' (to link 'User' and 'Achievement' models as you may guess).

So I tried using the "composite_primary_keys" gem. I followed all the instructions, nevertheless, the result wasn't like I expected. Seems like it doesn't create pkey in the 'user_achievement' table according to the info by psql tool:

test1_development=> \d user_achievements

Table "public.user_achievements"
Column | Type | Modifiers 

----------------+---------+-----------

user_id | integer | 
achievement_id | integer | 
uach_date | date | 

Indexes:

"index_user_achievements_on_achievement_id" btree (achievement_id)

"index_user_achievements_on_user_id" btree (user_id)

Foreign-key constraints:

"fk_rails_4efde02858" FOREIGN KEY (user_id) REFERENCES users(id)

"fk_rails_c44f5b3b25" FOREIGN KEY (achievement_id) REFERENCES achievements(id)

Here's models and migrations' code:

class CreateUsers < ActiveRecord::Migration[5.0]
 def change
  create_table :users do |t|
  t.string :name
  end
 end
end

class CreateAchievements < ActiveRecord::Migration[5.0]
 def change
  create_table :achievements do |t|
  t.string :ach_name
  t.text :ach_desc
  end
 end
end

class CreateUserAchievements < ActiveRecord::Migration[5.0]
  def change
   create_table :user_achievements, id: false do |t|
   t.belongs_to :user, :foreign_key => [:id]
   t.belongs_to :achievement, :foreign_key => [:id]
   t.date :uach_date
   end
  end
 end


class Achievement < ApplicationRecord
  has_many :user_achievements
end

class User < ApplicationRecord
  has_many :user_achievements
end

class UserAchievement < ApplicationRecord
  self.primary_keys = :user_id, :achievement_id
  belongs_to :user, :foreign_key => [:id]
  belongs_to :achievement, :foreign_key => [:id]
end

So should the gem alter db tables? or it influences just the rails' environment? Is there the only way to alter db - to add execute line in migration?

like image 331
Alexander Gorg Avatar asked Dec 14 '25 02:12

Alexander Gorg


1 Answers

Since nobody have posted anything useful, I'll share what I've got by now.

Gem 'composite_primary_key' (CPK) doesn't change anything in database, so if you still want it - you should do it manually (add the command to migration).

The only thing CPK does is extending Rails with 'understanding' what a composite primary key is, since it originally doesn't have and shows an error.

Anyway I found it is very sohpisticated and problematic to use composite primary keys in Rails apps because it makes using other gems quite nerveous (with every new gem installation you keep in mind that somewhere something can go wrong) as well as changing your code with cpks in future. Also it makes your code harder to understand for other people who are not familliar with this feature. So you should always specify that you have used CPK.

A very good alternative is adding an index with 'unique' option which technically means quite the same but doesn't require additional headache.

So use it only if you really have to and there's no other less sophisticated solution!

like image 86
Alexander Gorg Avatar answered Dec 15 '25 17:12

Alexander Gorg