Why do Rails migrations define foreign keys in the application but not in the database?

邮差的信 提交于 2019-11-28 04:54:13
Bill Karwin

Rails holds some conventions that enforcement of data integrity should be done in the application, not in the database.

For example, Rails even supports some database designs that cannot use foreign keys, such as Polymorphic Associations.

Basically, Rails conventions have treated the database as a static data storage device, not an active RDBMS. Rails 2.0 is finally supporting some more realistic features of SQL databases. It's no surprise that the result will be that developing with Rails will become more complex than it was in version 1.0.

After having worked with this issue for a while, I don't think it's part of the core Rails philosophy that foreign keys should not be enforced by the database.

The application level validations and checks are there to provide easy, quick, human readable (think error messages) checks that work in 99.99% of the time. If your application requires more than that, you should use database level constraints.

I think this "philosophy" evolved because of the original testing frameworks used: foreign keys just proved to be a gigantic hassle when using fixtures. It's like when a "bug" becomes a "feature" because no one fixes it. (If I'm misremembering history, someone correct me.)

At a minimum, there is a growing movement within the Rails community to enforce integrity with the database. Check out this blog post from last month. She even links to some plugins that help provide support for handling errors (and another blog post that links to more plugins). Do a few more Google searches; I've seen other plugins that add support to migrations to create foreign keys, too.

Now, what is part of the core Rails philosophy is: Don't worry about stuff unless you actually need to. For a lot of web applications, it's probably ok if a small (probably tiny) percentage of records contain invalid data. Pages that might be affected might only very rarely be viewed, or the error can be handled gracefully already. Or maybe it's cheaper (as in, cold hard cash) to handle problems by hand for the next 6 months as the application grows than it is to spend the development resources planning for every contingency now. Basically, if your use cases don't make it seem all important, and it can really only be caused by a race condition that may happen 1/10000000 requests... well, is it worth it?

So my prediction is that tools will spring up to handle the whole situation better by default, and eventually these will get merged into Rails 3. In the meantime, if your app really needs it, add them. It'll cause a slight testing headache, but nothing you can't get through with mocks and stubs. And if your app doesn't really need it... well you're all good already. :)

After many decades in the industry, I firmly believe that a good database design will save an application from many problems, especially when it undergoes enhancements. If it is known that a particular constraint will keep the database integrity even after a programming slip (I am sure that I am not the only one to do that), then it by all means should be applied to the database if possible. So I would encourage people to use foreign keys when ever possible. I would also consider using tests to provide data integrity. For we all know about murphy's law.

One mistake a lot of folks make is confusing migrations with the model. The migrations simply modify the database, and have nothing to do with the models you have defined. As a result of this confusion, a lot of foreign key plugins try combine the model with the migrations and do too much magical stuff.

For migrations, I'd use http://github.com/matthuhiggins/foreigner/tree/master. You shouldn't need to change your models to get foreign keys to work with Rails.

It does create a customer_id column (obviously). For the most part, though, Rails believes in enforcing constraints and validations at the application level, rather than the database level; that's why columns, by default, in Rails may contain NULL values, even if you have validates_presence_of or something like that. The view of Rails' developers is that such constraints should be handled by the application, not the database.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!