You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 15:00:26