【问题标题】:Rails model generation fails due to foreign key type由于外键类型,Rails 模型生成失败
【发布时间】:2020-02-10 19:57:14
【问题描述】:

我使用以下命令创建了一个模型:

rails g model UserCertification user:references certification:references certification_no:string

引用我的设计用户模型user:references

在 db:migrate 我收到以下错误: 原因:

ActiveRecord::MismatchedForeignKey: 列user_id 在表上 user_certificationsusers 上的列 id 不匹配,该列具有 输入bigint(20)。要解决此问题,请更改 user_id 上的 user_certifications 列是 :bigint。 (例如 t.bigint :user_id)。原始消息:Mysql2::Error: Cannot add 外键约束

这是我的迁移

class CreateUserCertifications < ActiveRecord::Migration[6.0]
  def change
    create_table :user_certifications do |t|
      t.references :user, null: false, foreign_key: true
      t.references :certification, null: false, foreign_key: true
      t.string :certification_no

      t.timestamps
    end
  end
end

我尝试使用t.references :user, null: false, foreign_key: true,type: :integer将类型设置为整数

我还删除了模型并重新制作并检查了以前的参考资料,但没有成功。 也许有人有想法?

【问题讨论】:

  • 您是否已经创建了用户表?
  • 奇怪。 type: :integer 将类型设置为整数,但不是 bigint。您可以尝试使用t.bigint :user_id, null: false 添加列,然后手动创建使用add_foreign_key :user_certifications, :users 添加fkey 约束
  • 根据6.0 docs默认为:bigint。这让这更加令人费解。

标签: ruby-on-rails rails-migrations ruby-on-rails-6


【解决方案1】:

尝试设置引用中的类型以匹配另一个表:

t.references(:user, null: false, type: :bigint)

如果这不起作用,请尝试在 user_certifications 中显式创建外键:

t.bigint :user_id, null: false
t.references(:user)

【讨论】:

  • t.references 同时创建列约束和外键约束。如果你想手动添加外键,你应该使用add_foreign_key :from, :toTableDefinition 中没有等价物。
  • t.references(:user, null: false, type: :bigint) 对这两种情况都有效。我不确定为什么这以前不起作用 - 发生了一些奇怪的事情。谢谢大卫!
  • 我刚碰到这个。有没有人弄清楚为什么会这样?如果两个迁移都是使用 Rails 6 生成的,则不必指定类型,因为 :bigint 已经是 :id 的默认类型,对吧?如果我们确实指定了一个类型,当然它可以解决问题,但我们不应该这样做,对吧?
  • 一年后我也遇到了这个问题。我需要返回并将 bigint 添加到我的迁移中吗?
【解决方案2】:

如果您在 Rails 6(可能还有其他版本)中看到此消息,则该错误消息可能具有误导性,并且与数据类型完全无关。

例如,在您的示例中,如果表 certifications 不存在(例如因为拼写错误),您仍然会收到声称 user_id 应该是 bigint 的错误消息,即使用户引用非常好。

系统地注释掉您的一些引用并运行 db:migrate 和 db:rollback 直到您确定实际失败的引用。然后仔细检查是否正确。

【讨论】:

【解决方案3】:

添加多个参考?

扩展已接受的答案:

t.references(:user, null: false, type: :bigint)

...如果您尝试添加多个引用,您可能会发现它仍然失败 - 但控制台错误仍会将您引导至第一个错误。

例如就我而言,我添加了四个引用

t.references(:user, null: false, type: :bigint)
t.references(:blog, null: false, type: :integer)
t.references(:post, null: false, type: :bigint)
t.references(:comment, null: false, type: :bigint)

t.references :user, null: false, type: :bigint
t.references :blog, null: false, type: :integer
t.references :post, null: false, type: :bigint
t.references :comment, null: false, type: :bigint

只更改第一个,控制台告诉我第一个(指定类型)不起作用,并给出与未指定类型相同的错误。

更改所有四个引用都成功,这只能让我得出结论,控制台错误是由第二个引用触发的,但显示第一个引用仍然是流氓,而不是有问题的引用(尚未更改的第二个参考)。

因此,如果您有多个参考,请将它们全部更改以匹配解决方案,(而不是期望控制台告诉您您编辑的 t.references 已成功,而您的第二个已失败。)

【讨论】:

    【解决方案4】:

    由于 Rails 6 中的 mismatched foreign keys reporting bug 非常混乱,我遇到了这个问题,

    基本上用MySQL,目前Rails可以针对表中的列错误报这个错误。

    有一个fix in the works,所以应该会在近期解决。

    如果您遇到此问题,则需要检查 create_table 语句中的所有引用,并查看是否有潜在的数据类型问题 - 考虑到 Rails 6 的新默认值是 bigint,但更旧表可能正在使用int

    【讨论】:

    • 我想说我很高兴你引用了这个。这个确切的错误发生在我身上——我有一个主键为string 类型的表,创建了另一个具有两个外键约束列的表,Rails 一直报告错误列的ActiveRecord::MismatchedForeignKey 错误。您提到这个 Rails 错误为我节省了很多调试时间。非常感谢。
    【解决方案5】:

    如果两个迁移都是使用 Rails 6.0 生成的,人们会假设不需要指定类型,因为:bigint 已经是:id 列的默认类型。在我的例子中,指定类型并没有让 Rails 高兴。添加仅添加引用的第二个迁移。

    class AddReferencesToUserCertifications < ActiveRecord::Migration[6.0]
      def change
        add_reference :user_certifications, :user, null: false, foreign_key: true
        add_reference :user_certifications, :certification, null: false, foreign_key: true
      end
    end
    

    【讨论】:

      猜你喜欢
      • 2014-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多