在ActiveRecord中创建外键约束

14

如何在ActiveRecord中创建外键?我在我的模型中有类似以下的代码:

class Student < ActiveRecord::Base
  attr_accessible :name, :level_id
  belongs_to :level
end

class Level < ActiveRecord::Base
  attr_accessible :number
  has_many :students
end

但是schema.rb和开发sqlite3数据库中都没有表明外键约束已经在level_id字段上设置。除了ActiveRecord或Rails之外,我需要手动做些什么吗?我有遗漏什么步骤吗?

使用的Rails版本为3.2.8。

5个回答

16

如果你正在使用Rails版本大于或等于4.2,且使用mysqlmysql2或者postgresql适配器,则可以在迁移中使用add_foreign_key方法,像这样:

# add a foreign key to `articles.author_id` referencing `authors.id`
add_foreign_key :articles, :authors

API 参考文档


15
你不需要使用外键约束来正确映射关系。你可以使用验证来确保Rails应用程序的数据完整性。
Rails迁移没有提供帮助程序来创建外键。您可以在迁移中创建自己的SQL约束,或使用Foreigner Gem。Foreigner将为迁移提供帮助程序方法以创建约束:
add_foreign_key(:students, :levels)

Foreigner gem看起来不错。那么Rails/ActiveRecord没有内置机制来处理这个吗? - at.
2
很遗憾,迁移将创建索引,但不会创建外键。来自http://guides.rubyonrails.org/migrations.html - “references助手实际上不会为您创建外键约束。您需要使用execute或添加外键支持的插件。” - mguymon
1
正如另一个答案所述,从Rails 4.2开始,确实支持添加外键约束 - http://edgeguides.rubyonrails.org/4_2_release_notes.html#foreign-key-support - Ben Coppock
6
虽然第一句话是正确的,但它并没有回答问题。许多开发人员会同意,拥有良好约束的数据库模式与依靠应用程序管理完整性一样重要,甚至更重要。这个答案会阻碍良好的数据库设计原则,我认为并不实用。 - Chris Noldus

3

1
这不是Rails内置的功能,Rails通过执行选择查询来模拟此行为,但SQL约束将保证引用完整性,将它们添加到代码中是一个好习惯。 - Edgar Ortega
你错了。如上所述,它确实创建了实际的外键约束。请参见此处:https://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/add_foreign_key - DB140141
1
我想我没有解释清楚,但你是对的。我的意思是,当添加引用列时,Rails不会自动添加外键,Rails内置了此功能,但您需要明确告诉迁移创建外键或使用add_foreign_key自己添加。 https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference - Edgar Ortega

2

在你的模型中添加belong_tohas_many行,可以让Rails意识到它们之间的关系并生成帮助方法,但不会在数据库级别上创建FK。为了做到这一点,你需要创建并运行一个迁移:

rails g migration add_level_id_to_students level_id:integer

然后运行rake db:migrate

如果您想生成一个带有外键部分的模型,可以使用references快捷方式: rails g model Student name:string level:references

请查看Rails指南获取更多信息!


1
我已经做了这些,关系正常。我问的是在数据库级别上的FK。因此,根据您的评论,听起来这是我应该在Rails/ActiveRecord之外添加的内容? - at.
1
这个问题特别询问在Rails/ActiveRecord之外流行的数据库级约束。虽然这个答案指定了在Rails/ActiveRecord中的做法,但它并没有解决那个问题。 - derick

2

3
请记住,索引不等于外键,您还需要添加foreign_key: true - Edgar Ortega

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接