我想为一个模型使用字符串主键,它充当另一个模型的外键。下面是两个模型定义:
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
初始化一个Topic对象,但是我不能保存它,因为它会导致这个错误:
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控制台中检索Topic项并保存它。
编辑:我设法解决这个权利之前,看到一个答复,这将是非常有帮助的。切换到Postgres后,列引用错误的问题变得更加清晰。我遇到的解决方案是在数据库迁移中为:foreign_key
选项提供一个哈希对象:
t.belongs_to :board, foreign_key: {primary_key: :name}, type: :string
型
现在一切都按预期进行。我想指出的是,在Rails documentation中没有任何地方说可以向外键选项提供散列(对于此方法);这是文档中反复出现的主题吗?
1条答案
按热度按时间lh80um4z1#
如果在您的sqlite控制台中,如果您执行
.schema topics
,您将看到外键指向boards(id)
。您还可以看到,您可以将任何board_id
值插入到topics
中,约束没有做任何事情,因为sqlite。您还将看到,如果尝试在适当的关系数据库中创建相同的外键,那么您将得到一个关于引用不存在的
boards.id
列的错误。AFAIK,Rails不支持这种安排。具有指向除
id
之外的其它关系中的任何字段的外键。foreign_key
选项必须有一些语法,如:foreign_key: { to_column: "name" }
个更新-来自OP
您需要向
foreign_key
选项传递一个选项哈希,如下所示:foreign_key: { primary_key: :name }
个