自定义表名的 belongs_to 关联的 Rails 迁移

206 阅读1分钟

TL;DR:提供to_table 选项,就像foreign_key: {to_table: :<table_name>}

当涉及到为一个belongs_to 关联的Rails迁移时,如果其名称与连接表的名称不一致,在阅读Rails文档或资料后,可能很难迅速找到如何做。这篇文章应该能帮到你。

让我们从下面的例子开始:

  • 系统中已经有了一个User 模型
  • 我们需要添加Payment 模型
  • Payment 应该属于一个 ,也就是 。receiver User

在代码中,它会看起来像这样:

class User < ApplicationRecord
end

class Payment < ApplicationRecord
  belongs_to :receiver, class_name: 'User'
end

让我们试着生成一个这个模型和一个迁移,按照文档的要求为它创建DB表:

rails g model payment receiver:references

这就产生了下面的迁移:

class CreatePayments < ActiveRecord::Migration[6.0]
  def change
    create_table :payments do |t|
      t.belongs_to :receiver, null: false, foreign_key: true
      t.timestamps
    end
  end
end

令人惊讶的是,rake db:migrate 产生了以下错误:

PG::UndefinedTable: ERROR:  relation "receivers" does not exist

原因很明显。这个迁移试图为一个不存在的表添加一个外键。它采用了关联名receiver ,并且默认为它指向一个复数的表receivers 。这并没有什么问题。除了一个事实,就是没有receivers 表,应该用users 表来代替。

不幸的是,在花了大量时间阅读文档后,人们甚至可能最终没有解决方案。在Rails代码的深处,很难发现例子中的某一行。因此,我在这里提供了一个解决方案:

class CreatePayments < ActiveRecord::Migration[6.0]
  def change
    create_table :payments do |t|
      t.belongs_to :receiver, null: false, foreign_key: {to_table: :users}
      t.timestamps
    end
  end
end

现在迁移运行时没有出现任何故障,并且产生了一个正确的结果,即创建的payments 表带有receiver_id 列和一个外键指向加入的users 表。

因此,解决方案是在上面的例子中使用foreign_key: {to_table: :users}