为什么 Rails 迁移在应用程序中定义外键,而不是在数据库中定义外键?

发布于 2024-07-22 06:31:25 字数 825 浏览 2 评论 0原文

如果我定义一个 CustomerOrder 模型,其中 Customer “有很多”OrdersOrder“属于”Customer,在 Rails 中,我们谈论 Order 通过 拥有指向 Customer 的外键customer_id 但我们并不意味着这是在数据库中强制执行的。

因为 Rails 没有将其定义为数据库级约束,所以存在数据完整性被破坏的风险,可能是在应用程序外部(或者如果您同时收到请求则在内部?),除非您在数据库中手动强制执行该约束。

为什么 Rails 不在数据库级别定义外键,或者有没有办法让 Rails 这样做?

class Customer < ActiveRecord::Base
  has_many :orders
end

class Order < ActiveRecord::Base
    belongs_to :customer
end

ActiveRecord::Schema.define(:version => 1) do

  create_table "customers", :force => true do |t|
    t.string   "name"
  end

  create_table "orders", :force => true do |t|
    t.string   "item_name"
    t.integer  "customer_id"
  end

end

If I define a Customer and Order model in which a Customer "has many" Orders and the Order "belongs to" the Customer, in Rails we talk about Order having a foreign key to the Customer through customer_id but we don't mean that this is enforced in the database.

Because Rails does not define this as a database-level constraint, there is a risk of your data's integrity being violated, perhaps outside the application (or inside if you receive simultaneous requests?), unless you enforce the constraint in the database manually.

Why does Rails not define the foreign key at the database level or is there a way to get Rails to do this?

class Customer < ActiveRecord::Base
  has_many :orders
end

class Order < ActiveRecord::Base
    belongs_to :customer
end

ActiveRecord::Schema.define(:version => 1) do

  create_table "customers", :force => true do |t|
    t.string   "name"
  end

  create_table "orders", :force => true do |t|
    t.string   "item_name"
    t.integer  "customer_id"
  end

end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

撩心不撩汉 2024-07-29 06:31:25

Rails 遵循一些约定,即应在应用程序中执行数据完整性,而不是在数据库中。

例如,Rails 甚至支持一些数据库设计 不能使用外键,例如多态关联。

基本上,Rails 约定将数据库视为静态数据存储设备,而不是活动的 RDBMS。 Rails 2.0终于支持 SQL 数据库的一些更实际的功能。 毫不奇怪,结果是使用 Rails 进行开发将变得比 1.0 版本更加复杂。

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.

恰似旧人归 2024-07-29 06:31:25

在解决这个问题一段时间后,我认为数据库不应该强制执行外键并不是 Rails 核心理念的一部分。

应用程序级别的验证和检查可提供简单、快速、人类可读(例如错误消息)的检查,并且在 99.99% 的情况下都有效。 如果您的应用程序需要更多,您应该使用数据库级别约束。

我认为这种“哲学”的演变是因为使用了原始的测试框架:外键在使用装置时被证明是一个巨大的麻烦。 这就像一个“错误”变成了“功能”,因为没有人修复它。 (如果我记错了历史,有人会纠正我。)

至少,Rails 社区内有越来越多的运动要求加强数据库的完整性。 查看上个月的这篇博文。甚至链接到一些有助于提供处理错误支持的插件(以及链接到更多插件的另一篇博客文章)。 多做几次谷歌搜索; 我见过其他插件也添加了对迁移创建外键的支持。

现在,Rails 核心理念的一部分是:除非确实需要,否则不要担心。 对于许多 Web 应用程序来说,如果一小部分(可能很小)的记录包含无效数据,这可能是可以接受的。 可能受影响的页面可能很少被查看,或者错误已经可以得到妥善处理。 或者,随着应用程序的增长,在接下来的 6 个月内手动处理问题可能比现在为每种意外情况花费开发资源进行计划更便宜(例如,现金)。 基本上,如果您的用例并没有使它看起来很重要,并且它实际上只能由可能发生 1/10000000 个请求的竞争条件引起……那么,值得吗?

所以我的预测是,默认情况下会出现一些工具来更好地处理整个情况,最终这些工具将合并到 Rails 3 中。同时,如果您的应用程序确实需要它,请添加它们。 它会导致轻微的测试头痛,但没有什么是你无法通过模拟和存根完成的。 如果您的应用程序并不真正需要它......那么您已经一切都很好了。 :)

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. :)

孤千羽 2024-07-29 06:31:25

在该行业工作了几十年后,我坚信良好的数据库设计可以使应用程序避免许多问题,特别是当它进行增强时。 如果知道特定的约束即使在编程失误之后也能保持数据库的完整性(我确信我不是唯一这样做的人),那么如果可能的话,无论如何都应该将其应用于数据库。 因此,我鼓励人们尽可能使用外键。 我还会考虑使用测试来提供数据完整性。 因为我们都知道墨菲定律。

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.

单调的奢华 2024-07-29 06:31:25

许多人犯的一个错误是将迁移与模型混淆。 迁移只是修改数据库,与您定义的模型无关。 由于这种混乱,许多外键插件尝试将模型与迁移结合起来,并做了太多神奇的事情。

对于迁移,我会使用 http://github.com/matthuhiggins/foreigner/tree/master 。 您不需要更改模型即可让外键与 Rails 一起使用。

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.

面犯桃花 2024-07-29 06:31:25

它确实创建了一个 customer_id 列(显然)。 不过,在大多数情况下,Rails 相信在应用程序级别而不是数据库级别强制执行约束和验证; 这就是为什么默认情况下 Rails 中的列可能包含 NULL 值,即使您有 validates_presence_of 或类似的值。 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文