我想对一个模型使用字符串主键,该主键充当另一个模型的外键.以下是两个模型定义:

class Board < ApplicationRecord
  self.primary_key = :name
  has_many :topics, primary_key: :name
end

class Topic < ApplicationRecord
  belongs_to :board, primary_key: :name
end

下面是相应的数据库迁移:

class CreateBoards < ActiveRecord::Migration[7.0]
  def change
    create_table :boards, id: :string, primary_key: :name do |t|
      t.timestamps
    end
    create_table :topics do |t|
      t.belongs_to :board, foreign_key: true, type: :string
      t.timestamps
    end
  end
end

我可以用b = Board.create(name: "test")来创建一个Board对象,并且可以用t = b.topics.new来初始化一个Theme对象,但我不能保存它,因为它会导致以下错误:

irb(main):002:0> t = b.topics.new
=> #<Topic:0x0000558d9e1ddea0 id: nil, board_id: "test", created_at: nil, updated_at: nil>
irb(main):003:0> t.save
  TRANSACTION (0.2ms)  begin transaction
  Topic Create (1.0ms)  INSERT INTO "topics" ("board_id", "created_at", "updated_at") VALUES (?, ?, ?)  [["board_id", "test"], ["created_at", "2023-08-01 09:57:21.876835"], ["updated_at", "2023-08-01 09:57:21.876835"]]
  TRANSACTION (0.1ms)  rollback transaction
/var/lib/gems/3.0.0/gems/sqlite3-1.6.3-x86_64-linux/lib/sqlite3/database.rb:152:in `initialize': SQLite3::SQLException: foreign key mismatch - "topics" referencing "boards" (ActiveRecord::StatementInvalid)
/var/lib/gems/3.0.0/gems/sqlite3-1.6.3-x86_64-linux/lib/sqlite3/database.rb:152:in `initialize': foreign key mismatch - "topics" referencing "boards" (SQLite3::SQLException)

尽管Rails在抱怨,但我可以在数据库控制台中很好地使用命令INSERT INTO "topics" ("board_id", "created_at", "updated_at") VALUES ("test", "2023-08-01 09:57:21.876835", "2023-08-01 09:57:21.876835");.我甚至可以在Rails控制台中检索主题项并保存它.

Edit:在看到一个非常有帮助的回复之前,我设法解决了这个问题.在切换到Postgres之后,不正确的列引用的问题变得更加明显.我想到的解决方案是为数据库迁移中的:foreign_key选项提供一个散列对象:

t.belongs_to :board, foreign_key: {primary_key: :name}, type: :string

现在一切都按预期进行了.我想指出的是,Rails documentation中没有哪个地方说哈希可以提供给外键选项(对于这个方法);这是文档中反复出现的主题吗?

推荐答案

如果在您的SQLite控制台中,如果执行.schema topics,您将看到外键指向boards(id)...您还会看到,您可以将任何board_id值插入到topics中,约束不会做任何事情,因为SQLite.

您还将看到,如果try 在适当的关系数据库中创建相同的外键,则会出现引用不存在的boards.id列的错误.

AFAIK,Rails不支持这种排列,即.具有指向除id之外的其他关系中的任何字段的外键.foreign_key选项必须有一些语法,如:foreign_key: { to_column: "name" }

更新-自操作

您需要将选项散列传递给foreign_key选项,如:foreign_key: { primary_key: :name }

Ruby-on-rails相关问答推荐

错误AESGCMOpen获取密码:消息身份验证失败:Golang解密GCM

根据表单内的 Select 字段值渲染部分内容

Turbo-Rails:如何将 Turbo Frame 添加到 `application.html.erb`?

has_many 通过大小验证

为什么有时会出现类型错误没有将 StringIO 隐式转换为 String?Ruby /导轨

如何避免 activesupport 中的循环参数引用警告

heroku 推送错误:无法检测到 rake 任务

在 Rails 3 中,如何在路由中使用锚点作为 ID?

向现有控制器添加操作(Ruby on Rails)

如何配置设计以使用自定义邮箱布局?

rails:防止闪烁消息显示两次

Rails 模型:您将如何创建一组预定义的属性?

是否可以在 Rails 中否定范围?

在 Controller 中调用模型方法

在本地 Rails 开发环境中获取真实 IP 地址

rails回形针和乘客`'识别'命令无法识别`

在 RoR 中引用同一个表的多个外键

设计/Rails - 如何删除特定的 Flash 消息? (登录成功)

Ruby中的参数化获取请求?

使用连接的 Ruby on Rails ActiveRecord 查询