ruby-on-rails Ruby on Rails -外键不匹配

holgip5t  于 2023-08-08  发布在  Ruby
关注(0)|答案(1)|浏览(158)

我想为一个模型使用字符串主键,它充当另一个模型的外键。下面是两个模型定义:

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中没有任何地方说可以向外键选项提供散列(对于此方法);这是文档中反复出现的主题吗?

lh80um4z

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 }

相关问题