【问题标题】:add_foreign_key not creating foreign keysadd_foreign_key 不创建外键
【发布时间】:2018-10-07 10:33:13
【问题描述】:

我正在使用 Rails 5.1 和 SQLite。以下迁移未按预期工作。

class AddJobTitleForeignKeyToTimeOffTypes < ActiveRecord::Migration[5.1]
  def change
    add_column :time_off_types, :job_title_id, :integer
    add_foreign_key :time_off_types, :job_title, :column => :job_title_id
  end
end

它在“time_off_types”表中创建列“job_title_id”,但不创建外键。

【问题讨论】:

  • job_title_id 是这里的外键。 add_foreign_key 将在time_off_types 表中的job_title_id 列和数据库级别的“job_titles”表的id 列之间创建一个外键映射。 Here 是关于此主题的有用博客文章
  • @KarthikRavichandran 你解释的正是我想要它做的,但我做错了什么?
  • 第一列是什么?只做第二行:add_foreign_key :time_off_types, :job_titles

标签: ruby-on-rails sqlite ruby-on-rails-5


【解决方案1】:

ActiveRecord 的add_foreign_key 方法在表创建之外使用,因此使用ALTER TABLE ... ADD CONSTRAINT ...

SQLite 的ALTER TABLE 不支持添加(任何类型的)约束。 (值得回顾一下,因为 SQLite 中的 ALTER TABLE 可能比您预期的更受限制。例如,SQLite 3.25.0 也无法重命名列。)

但是,SQLite CREATE TABLE 确实支持外键约束,ActiveRecord 迁移 create_table #references 方法可以创建它们:

def change
  create_table :pets do
    t.references :owner, foreign_key: true
    ...
  end
end

Rails 迁移指南没有提到这种差异。

那么这是如何工作的呢?

ActiveRecord 数据库适配器有两种方法:supports_foreign_keys?supports_foreign_keys_in_create?,默认情况下都是 false(请参阅 Rails API 文档)。

add_foreign_key returns immediately 除非supports_foreign_keys?true,但对于SQLite 是false,所以add_foreign_key 的路径结束。

另一方面,supports_foreign_keys_in_create? is true 用于 SQLite >= 3.6.19,它允许 #references 方法使用 CREATE TABLE ... 创建外键。

(我已链接到 Rails 5.1 代码,因为这就是您在提问时使用的代码,但直到今天的 Rails 5.2.1 仍然如此。)

【讨论】:

  • hmm... 我使用的是 ActiveRecord 5.2,带有 sqlite 3.27.2,它似乎没有在 SQL 模式中添加外键约束,也没有反映在 schema.rb 中。正如你所说,supports_foreign_keys? 返回 falsesupports_foreign_keys_in_create 返回 true。但即使我在create_table 中使用t.references,它似乎也没有为表生成正确的SQL...
  • 原来,sqlite3 适配器中有一个错误,当表被更改时会丢失外键:github.com/rails/rails/issues/33520 似乎是一个修复,但我 认为 i> 它是针对 v6 的。
猜你喜欢
  • 2018-01-05
  • 1970-01-01
  • 1970-01-01
  • 2012-08-10
  • 1970-01-01
  • 1970-01-01
  • 2013-02-10
  • 1970-01-01
  • 2021-09-13
相关资源
最近更新 更多