While working on GoRunNow this weekend I ran headlong into the issue of foreign key constraints in Rails. In short, the creation of foreign key constraints is not supported by Rails out of the box. (There are plugins to add support, but I’m trying to keep my plugin usage to a minimum.)

Of course, you can execute raw SQL in your migrations via the execute method, which is what I initially did. The surprise came when I started writing specs and discovered the associated model could be saved without the foreign key. I was expecting the database constraint to prevent this.

After an hour of head scratching and digging I discovered the catch is your test database gets created from schema.rb, which is generated via inflection on the database schema after migrations are applied. It’s not based on the migrations themselves, so those foreign key constraints created via execute are sneakily left out of schema.rb.

From what I’ve read the reason for doing this is speeding up tests, which makes sense, but it was rather surprising behavior for someone new to BDD in Rails.