如何在ActiveRecord中创建关联复合主键表的引用关联?
ActiveRecord中关联复合主键表的正确方式
问题场景
已创建带复合主键的wines表:
class CreateWines < ActiveRecord::Migration[7.1] def change create_table :wines, primary_key: [:name, :producer_id] do |t| t.string :name t.timestamps end end end
尝试创建wine_items表建立一对多关联,初始迁移代码:
class CreateWineItems < ActiveRecord::Migration[7.1] def change create_table :wine_items do |t| t.string :vintage t.references :wine, null: false, foreign_key: true end end end
执行db:migrate时报错:
PG::UndefinedColumn: ERROR: column "id" referenced in foreign key constraint does not exist
修改后尝试指定复合主键参数:
class CreateWineItems < ActiveRecord::Migration[7.1] def change create_table :wine_items do |t| t.string :vintage t.references :wine, null: false, foreign_key: { column: [:name, :producer_id], primary_key: [:name, :producer_id] } t.timestamps end end end
仍报错:
For composite primary keys, specify :column and :primary_key, where :column must reference all the :primary_key columns from "wines"
解决方案
ActiveRecord的t.references/t.belongs_to默认仅支持单一主键关联,处理复合主键需手动创建外键列+显式添加复合外键约束,具体步骤如下:
1. 修正迁移文件
放弃t.references,手动创建与wines复合主键对应的列,再添加复合外键:
class CreateWineItems < ActiveRecord::Migration[7.1] def change create_table :wine_items do |t| t.string :vintage # 手动创建对应wines复合主键的外键列(命名可自定义,建议清晰关联) t.string :wine_name t.bigint :wine_producer_id t.timestamps end # 添加复合外键约束,列的顺序必须与wines的主键顺序完全匹配 add_foreign_key :wine_items, :wines, columns: [:wine_name, :wine_producer_id], primary_key: [:name, :producer_id] end end
2. 配置模型关联
在模型层需明确指定复合主键和外键列,确保关联生效:
Wine模型
class Wine < ApplicationRecord # 声明复合主键 self.primary_keys = :name, :producer_id # 定义一对多关联,指定外键列 has_many :wine_items, foreign_key: [:wine_name, :wine_producer_id], primary_key: [:name, :producer_id] end
WineItem模型
class WineItem < ApplicationRecord # 定义多对一关联,指定外键和关联表的主键 belongs_to :wine, foreign_key: [:wine_name, :wine_producer_id], primary_key: [:name, :producer_id] end
内容的提问来源于stack exchange,提问作者John Fadria
相关产品推荐
相关产品推荐

