我想对一个模型使用字符串主键,该主键充当另一个模型的外键.以下是两个模型定义:
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中没有哪个地方说哈希可以提供给外键选项(对于这个方法);这是文档中反复出现的主题吗?