I’ve got a Rails 3 app that I’m working on. I’m using the composite_primary_keys gem for a few tables, but Rails is still creating an id field that’s not being used (i.e. it’s nil for each entry). While it runs on my local machine in SQLite3, I can’t run the app on Heroku. Postgresql throws a fit at me and gives me this error:
2012-05-31T21:12:36+00:00 app[web.1]: ActiveRecord::StatementInvalid (PG::Error: ERROR: null value in column "id" violates not-null constraint
2012-05-31T21:12:36+00:00 app[web.1]: app/controllers/items_controller.rb:57:in `block (2 levels) in create'
2012-05-31T21:12:36+00:00 app[web.1]: : INSERT INTO "item_attr_quants" ("attribute_id", "created_at", "id", "item_id", "updated_at", "value") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "item_id","attribute_id"):
Since the “id” field is nil, Postgresql’s yelling at me.
Is there a way I can prevent the “id” field from being created in the first place, delete the column using a raw SQL statement, force Postgresql on Heroku to allow the “id” field to be null, or get around this some other way? I’m dead-set on using composite primary keys, so I don’t want to delete the gem and rewrite code.
Model
class ItemAttrQuant < ActiveRecord::Base
belongs_to :item
belongs_to :attribute
self.primary_keys = :item_id, :attribute_id
end
Migration
class CreateItemAttrQuants < ActiveRecord::Migration
def change
create_table :item_attr_quants do |t|
t.belongs_to :item
t.belongs_to :attribute
t.integer :value
t.timestamps
end
add_index :item_attr_quants, :item_id
add_index :item_attr_quants, :attribute_id
end
end
You can use the
:id => falseand:primary_keyoptions tocreate_tablein your migration:That will create
item_attr_quantswithout theidcolumn but your table won’t have a real primary key. You could add fake one by specifyingnot nullforitem_idandattribute_idand adding a unique index on those two columns:I don’t think ActiveRecord fully understands the notion of a real composite primary key inside the database so a unique index is AFAIK the best you can do unless you want to manually send an ALTER TABLE into the database.