1

This is a build on a question I asked before (without any luck).

I have a model where I'm using a string as a primary key:

class Employee < ActiveRecord::Base
   self.primary_key = "employment_id"
end 

This table also contains the Rails default 'id' field, with a uniqueness constraint.

When I add a new employee locally it all works fine, with Rails automatically generating a new unique id.

However when I run this on Heroku Postgres it appears to treat 'id' and 'employment_id' as the same field. I tried to get around this by manually setting a unique id, but still get this behaviour:

Employee.new do |s|

  max_id = Employee.maximum(:id)  
  puts max_id.to_s             # => 1803 

  s.employment_id = "fred_01"      
  s.id = max_id + 1 

  puts employment_id.to_s      # => 1804

end

I'm running postgres 9.1.3 locally (and Heroku is on 9.1.4). I'm on Rails 3.2.3.

My questions are:

  • Any idea what's going on here?
  • Do you think it's right that I'm using employment_id as the primary key?
  • Would help if I deleted the 'id' field?
  • Is there any other best practice you would recommend?

Thanks for your help!

Derek.

Edit:

Adding migration file as requested:

class CreateEmployees < ActiveRecord::Migration
  def change
    create_table :employees do |t|
      t.string :employment_id, :unique => true
      etc...
    end
  end
end

EDIT

Very kind of nobody to point this out, but it's clear to me now that the real answer is "Just because you can, doesn't mean you should!"

Community
  • 1
  • 1
Derek Hill
  • 5,965
  • 5
  • 55
  • 74

2 Answers2

1

According to this post, it should solve the problem:

class CreateEmployees < ActiveRecord::Migration
  def change
    create_table :employees, {:id => false} do |t|
      t.string :employment_id, :unique => true
      etc...
    end
  end
  execute "ALTER TABLE employees ADD PRIMARY KEY (employment_id);"
end

Also in your model:

class Employee < ActiveRecord::Base
  set_primary_key :employment_id
  ...
end
Community
  • 1
  • 1
gabrielhilal
  • 10,660
  • 6
  • 54
  • 81
  • Great stuff. Much appreciated! – Derek Hill Jul 20 '12 at 14:47
  • If you're using rails 3.2 or higher, the set_primary_key method was deprecated. The Rails 3.2 release notes - Section 8.1 and it suggests using an assignment method instead like "self.primary_key= : employment_id" – Jade Hamel Feb 22 '16 at 19:33
1

An update for Rails 4.2.0 and Postgres in case it helps anyone...

Put a id: :string in the create_table options:

class FooMigration < ActiveRecord::Migration
  def change
    create_table :foo, id: :string do |t|
      t.string :name, null: false
      t.timestamps null: false
    end
  end
end

rake db:migrate

== 20150225043441 FooMigration: migrating ===========================
-- create_table(:foo, {:id=>:string})    -> 0.0031s
== 20150225043441 FooMigration: migrated (0.0032s) ==================

rails db (and \d foo)

psql (9.3.6)
Type "help" for help.

bar_development=# \d foo
                  Table "public.foo"
   Column   |            Type             | Modifiers 
------------+-----------------------------+-----------
 id         | character varying           | not null
 name       | character varying           | not null
 created_at | timestamp without time zone | not null
 updated_at | timestamp without time zone | not null
Indexes:
    "foo_pkey" PRIMARY KEY, btree (id)

I end up with a 'not null' string column with a primary key index.

Using a column name other than id is more involved.

Edit (26 Feb 2015): there seems to be a bug in rails when it generates the schema.rb file. It will not record the custom primary key state, you'll need to go in and edit it to add the id: :string option to the create_table call.

ie.

create_table "foo", id: :string, force: :cascade do |t|
  t.string   "name",       null: false
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

The crappy part: that change will be undone every time you do a migration. You'd have to keep a close eye on the file content (or write a test :) ).

The bug is fixed in PR 18228, merged to rails:master on Jan 3, 2015.

Lucas Nelson
  • 2,511
  • 1
  • 17
  • 14