簡體   English   中英

Rails 中的自定義名稱外鍵導致“ActiveRecord::InvalidForeignKey:PG::ForeignKeyViolation”錯誤

[英]Custom name foreign key in Rails causing 'ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation' error

我有一Book model,我有一個User model。 我正在嘗試在books表中創建一個名為author_id的新列,它實際上是users表的外鍵。

我關注了 Joshua Frankel 的這篇文章 但我收到以下錯誤

ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR`

我正在使用 Rails4.2


db/migrate/20191112111409_add_author_to_books.rb:

class AddAuthorToBooks < ActiveRecord::Migration
  def up
    add_reference :books, :author, references: :users, index: false
    commit_db_transaction
    add_index :books, :author_id, algorithm: :concurrently
    add_foreign_key :books, :users, column: :author_id
  end

  def down
    remove_column :books, :author_id
  end
end

應用程序/模型/book.rb:

class Book < ActiveRecord::Base
  belongs_to :author, class_name: :User, foreign_key: :author_id
end

應用程序/模型/user.rb:

class User < ActiveRecord::Base
  has_many :books, foreign_key: :author_id
end

Rails 控制台中的錯誤:

> user = FactoryBot.create(:user)
> book = FactoryBot.create(:book)
> book.author = user
> book.save
ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR:  insert or update on table "books" violates foreign key constraint "fk_rails_13be98de92"
DETAIL:  Key (author_id)=(1) is not present in table "users".
: UPDATE "books" SET "author_id" = $1, "updated_at" = $2 WHERE "books"."id" = $3
from ~/.ruby-gemset/ruby/2.3.0/gems/activerecord-4.2.11.1/lib/active_record/connection_adapters/postgresql_adapter.rb:602:in `exec_prepared'
Caused by PG::ForeignKeyViolation: ERROR:  insert or update on table "books" violates foreign key constraint "fk_rails_13be98de92"
DETAIL:  Key (author_id)=(1) is not present in table "users".

from ~/.ruby-gemset/ruby/2.3.0/gems/activerecord-4.2.11.1/lib/active_record/connection_adapters/postgresql_adapter.rb:602:in `exec_prepared'
>

在數據庫級別檢查數據庫 [外鍵] 完整性。 當您嘗試保存一book時,數據庫中沒有這樣的user

因此,在保存鏈接到他們的book之前,將user保存到數據庫。

user = FactoryBot.create(:user)
user.save # this

book = FactoryBot.create(:book)
book.author = user
book.save

我發現了這個問題。 它與 Postgres 中的模式有關。

我在 Postgres 數據庫中使用 Apartment gem 進行租賃。 就我而言, books是租用的。 但是, users表沒有被租用——它們是通用的。 意思是, user存在於public模式中,但book存在於(比方說) Malaysia模式中。

所以,當我們試圖保存book.save! books表(在Malaysia模式中)在相同模式(即Malaysia模式)的users表中檢查 id 為 1 的用戶。 但是,由於我的用戶實際上存在於public模式中,它認為沒有 id 為 1 的用戶(因為它只在Malaysia模式中尋找它)。

然后我在公寓中遇到了這個關於跨模式外鍵的已知問題


我是如何解決的?

  • 我將我的數據庫遷移一步回滾到基本上是通過刪除新的author_id列來恢復我的更改。
  • 然后從遷移文件中刪除了add_foreign_key語句,這樣 Postgres 表就不會創建任何 db 級別的外鍵關聯。
  • 然后再次運行遷移。

所以現在,我確實有一個名為author_id的新列(它也被索引),但它沒有users表的數據庫級外鍵。 然后規范優雅地通過了。

因此,它不再是真正的一流 db 級外鍵。 它只是依賴於 model 中定義的 Rails 關聯來實現我們想要的“外鍵”行為 - 效果很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM