0

I want to use custom primary key for a table, and referencing that table in other table. But i got rails PG::UndefinedColumn: ERROR: column "id" custom column error with my code

schema.rb

  create_table 'memberships', id: false, primary_key: :rank, force: :cascade do |t|
    t.string 'rank'
    t.integer 'discount_rate'
    t.datetime 'created_at', precision: 6, null: false
    t.datetime 'updated_at', precision: 6, null: false
  end

  create_table 'members', force: :cascade do |t|
    t.references :membership, index: true, foreign_key: { on_delete: :cascade }
    t.string 'name'
    t.datetime 'created_at', precision: 6, null: false
    t.datetime 'updated_at', precision: 6, null: false
  end

membership.rb

class Membership < ApplicationRecord
  has_many :members, foreign_key: :membership_rank
  validates :rank, uniqueness: true
end

member.rb

class Member < ApplicationRecord
  belongs_to :membership
  validates :name, length: { maximum: 30 }, uniqueness: true, presence: true
end  

I checked on rails c and found that my members are created with membership_id = 0.

How can i fix my code for my member table to reference membership table's rank column?

====

Rails + Postgres Relation Issue With Custom Foreign Key

Specifying column name in a "references" migration

I searched on google, but these kind of answer not worked on my code.

Thanks for all advice.

ddzxc
  • 25
  • 4
  • Did you consider that `rank` must contain unique values? Postgres will not let you setup a foreign key to a column without a unique index and `id: false` will prevent the generation of the unique index. If you really want to go down this rabbit hole you would have to use `create_table 'memberships', id: :string, primary_key: :rank, force: :cascade` add the unique constraint manually or not have a foreign key constraint. Whatever the actual problem is here - this isn't the solution. Rethink it. – max Feb 22 '23 at 22:23
  • *I want to use custom primary key for a table* -- why? – mechnicov Feb 22 '23 at 22:54

1 Answers1

1

If you really want to do this you need a unique index on memberships.rank:

class CreateMemberships < ActiveRecord::Migration[7.0]
  def change
    create_table 'memberships', id: :string, primary_key: :rank, force: :cascade do |t|
      t.integer :discount_rate
      t.timestamps
    end
  end
end

Postgres won't actually let you add foreign key constraints otherwise.

And then you need to add the column and foreign keys manually as add_reference doesn't let you specify the name of the column:

class CreateMembers < ActiveRecord::Migration[7.0]
  def change
    create_table 'members', force: :cascade do |t|
      t.string :membership_rank
      t.string :name
      t.timestamps
    end
    add_foreign_key :members, :memberships, 
      column: :membership_rank, 
      on_delete: :cascade, 
      primary_key: :rank
    add_index :members, :membership_rank
  end
end

However you're most likely just going to run into the next problem which is when you try insert non-unique data into memberships.rank.

You don't actually need this. Don't do it.

max
  • 96,212
  • 14
  • 104
  • 165
  • 1
    Only comment is the last 2 sentences should be on their own line preceded by an octothorp. (# You don't actually need this. Don't do it.) – engineersmnky Feb 24 '23 at 00:03