I'm using Rails migrations to manage a database schema, and I'm creating a simple table where I'd like to use a non-integer value as the primary key (in particular, a string). To abstract away from my problem, let's say there's a table employees
where employees are identified by an alphanumeric string, e.g. "134SNW"
.
I've tried creating the table in a migration like this:
create_table :employees, {:primary_key => :emp_id} do |t|
t.string :emp_id
t.string :first_name
t.string :last_name
end
What this gives me is what seems like it completely ignored the line t.string :emp_id
and went ahead and made it an integer column. Is there some other way to have rails generate the PRIMARY_KEY constraint (I'm using PostgreSQL) for me, without having to write the SQL in an execute
call?
NOTE: I know it's not best to use string columns as primary keys, so please no answers just saying to add an integer primary key. I may add one anyway, but this question is still valid.
I found a solution to this that works with Rails 3:
The migration file:
And in the employee.rb model:
This works:
It may not be pretty, but the end result is exactly what you want.
After nearly every solution which says "this worked for me on X database", I see a comment by the original poster to the effect of "didn't work for me on Postgres." The real issue here may in fact be the Postgres support in Rails, which is not flawless, and was probably worse back in 2009 when this question originally posted. For instance, if I remember correctly, if you're on Postgres, you basically can't get useful output from
rake db:schema:dump
.I am not a Postgres ninja myself, I got this info from Xavier Shay's excellent PeepCode video on Postgres. That video actually overlooks a library by Aaron Patterson, I think Texticle but I could be remembering wrong. But other than that it's pretty great.
Anyway, if you're running into this problem on Postgres, see if the solutions work in other databases. Maybe use
rails new
to generate a new app as a sandbox, or just create something likein
config/database.yml
.And if you can verify that it is a Postgres support issue, and you figure out a fix, please contribute patches to Rails or package your fixes in a gem, because the Postgres user base within the Rails community is pretty large, mainly thanks to Heroku.
How about this solution,
Inside Employee model why can't we add code that will check for uniqueness in coloumn, for ex: Assume Employee is Model in that you have EmpId which is string then for that we can add ":uniqueness => true" to EmpId
I am not sure that this is solution but this worked for me.
Unfortunately, I've determined it's not possible to do it without using
execute
.Why it doesn't work
By examining the ActiveRecord source, we can find the code for
create_table
:In
schema_statements.rb
:So we can see that when you try to specify a primary key in the
create_table
options, it creates a primary key with that specified name (or, if none is specified,id
). It does this by calling the same method you can use inside a table definition block:primary_key
.In
schema_statements.rb
:This just creates a column with the specified name of type
:primary_key
. This is set to the following in the standard database adapters:The workaround
Since we're stuck with these as the primary key types, we have to use
execute
to create a primary key that is not an integer (PostgreSQL'sserial
is an integer using a sequence):And as Sean McCleary mentioned, your ActiveRecord model should set the primary key using
set_primary_key
:Adding index works for me, I'm using MySql btw.