如何通过更新迁移与模型文件为现有表添加跨Gem外键字段?
给
to_do_items表添加completed_by外键的实现方案 嘿,我看你是想给现有的to_do_items表加一个completed_by外键字段,关联到其他Gem提供的模型对吧?下面分迁移文件和模型文件两部分,结合两种常见的关联场景给你说明正确的写法:
一、迁移文件的编写
首先要注意:如果你的表已经存在(已经执行过创建表的迁移),绝对不要修改旧的迁移文件,而是要新建一个迁移来添加字段,这样团队里的其他成员才不会出现数据库不一致的问题。
场景1:关联到普通的单表模型(非多态)
如果其他Gem提供的是普通的ActiveRecord模型(比如User或者Person),新建的迁移应该这样写:
class AddCompletedByToToDoItems < ActiveRecord::Migration[6.0] def change # 这里的to_table要替换成目标模型对应的数据库表名 add_reference :to_do_items, :completed_by, null: true, foreign_key: { to_table: :users } end end
要是你还没执行创建表的迁移,想在创建表的时候直接加上这个字段,那可以用你原来的代码,但要修正外键的指向:
class CreateToDoItems < ActiveRecord::Migration[6.0] def change create_table :to_do_items do |t| t.references :event, null: false, foreign_key: true t.integer :priority t.string :name t.boolean :done t.date :issued_on t.date :to_complete_on t.string :comment # 替换to_table的值为目标模型的表名 t.references :completed_by, null: true, foreign_key: { to_table: :users } t.text :description t.timestamps end end end
场景2:关联到多态模型(比如你已有的PersonCompany)
如果completed_by要关联的是多态模型(比如你代码里已经有的PersonCompany),那需要添加两个字段(id和type),迁移代码可以简化成这样:
class AddCompletedByPolymorphicToToDoItems < ActiveRecord::Migration[6.0] def change add_reference :to_do_items, :completed_by, polymorphic: true, null: true end end
二、模型文件的对应更新
根据你选择的关联场景,更新ToDoItem模型:
场景1:关联普通模型
添加对应的belongs_to关联,注意要指定class_name(如果模型不在默认命名空间下),并且因为字段允许为空,要加optional: true:
class ToDoItem < ApplicationRecord belongs_to :event belongs_to :person_company, polymorphic: true # 把class_name替换成其他Gem提供的模型类名,比如'SomeGem::User' belongs_to :completed_by, class_name: 'User', optional: true end
场景2:关联多态模型
添加多态的belongs_to关联,同样加上optional: true:
class ToDoItem < ApplicationRecord belongs_to :event belongs_to :person_company, polymorphic: true belongs_to :completed_by, polymorphic: true, optional: true end
几个关键提醒
- 永远不要修改已经执行过的迁移文件,新增字段就新建迁移,这是Rails开发的最佳实践。
- 一定要确认目标模型的表名和类名是否正确,尤其是其他Gem提供的模型,可能带有命名空间(比如
Devise::User),这时候class_name要写完整的类名,to_table要写对应的数据库表名(比如users)。 - 因为你设置了
null: true,所以关联必须加上optional: true,不然Rails会默认要求这个关联必须存在,导致保存时报错。
内容的提问来源于stack exchange,提问作者dani
相关产品推荐
相关产品推荐

