You Should Use Foreign Key Constraints in Rails
Updated 4/24/09: If you want to use foreign keys in your Rails project, checkout the migration_helpers and sexy_migrations plugins for a couple of options.
Jeff from Softies on Rails recommends doing without foreign keys and posted You Don’t Need Foreign Key Constraints In Rails to ask for our opinions.
He’s right. You don’t need foreign key constraints, just like you don’t need a seatbelt in your car. Your car will drive perfectly fine without one. You can drive cross-country at 120 miles per hour without a seatbelt, but may the Flying Spaghetti Monster have mercy on your soul you if you hit a tree.
It looks like everyone is on the FK side so far in the discussion. Of course, DHH hasn’t commented yet, so that may change. Rails is notorious for being “opinionated software”, and this is one of those opinions that a lot of people happen to disagree with, and is one of very few (the only?) cases where the majority of Rails users overwhelmingly, strongly disagree with the Rails philosophy.
One argument against FKs is that Rails’ ActiveRecord provides nifty relationship wiring and validation utilities, like belongs_to, has_many, and has_and_belongs_to_many. Since this logic is defined in the model, repeating it in the database is not DRY. Plus, FKs make it harder to deal with complicated relationships. You can’t delete an entity without first deleting its child entities (which :dependent => :destroy will do for you if you want closure).
These aren’t bad reasons, but they’re not good enough to outweigh the benefits of foreign keys, or to offset the potential cost of a weird bug that creates inconsistent data. A fairly common problem in Rails with foreign keys is setting up and tearing down test fixtures — but let’s face it, fixtures pretty much suck, and there are ways to deal with the problem. Referential integrity is more important than cheap, lazy fixtures.
Foreign keys may repeat something that’s already defined in the model code, but so what? Relationships rarely change, and when they do, you’re probably going to be changing the database anyway. It’s not as if they’re likely to get out of sync.
Foreign keys are pretty easy to create, especially if you use a plugin like sexy migrations, and they don’t add much overhead. (Oddly, Rails 2.0 borrowed quite a bit from sexy migrations but didn’t include the foreign key stuff.)
Some databases provide the option to automatically index the columns that are foreign keys, saving you the trouble of adding the indexes yourself. (Foreign keys tend to be columns that you’d want to index. Consider fetching a post’s comments: SELECT * FROM comments WHERE post_id = 1 should use an index on post_id.)
And of course, without foreign keys how can you generate an ER diagram to hang on the wall for everyone to admire? (Note: I don’t do that.)