ERROR: delete on table violates foreign key constraint. Key id is still referenced from table (many)

ERROR: delete on table violates foreign key constraint. Key id is still referenced from table (many)

我正在使用 Rails 和 PostgreSQL,并且有一个基本的一对多关系,一个 Auction 有很多 Bid。但是,当我尝试删除拍卖(存在出价)时,出现以下错误:

ERROR: update or delete on table "auctions" violates foreign key constraint "fk_rails_43e9021cbf" on table "bids". DETAIL: Key(id)=(1) is still referenced from table "bids".

删除没有出价的拍卖不会出错。

让我感到困惑的部分是在我的 Auction 模型中,我有:

has_many :bids, dependent: :destroy

既然我有一个 dependent destroy 子句,为什么我仍然会收到这个错误?

编辑: 我试过删除整个数据库,然后 recreating/re-migrating 一切 - 仍然得到同样的错误。

您的错误来自数据库,而不是 rails。您需要先在您的应用程序中删除出价或更改数据库中的外键约束以级联删除

您是使用 delete 还是 destroy 删除对象?我认为您正在使用 delete 并且您想使用 destroy

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Delete+or+destroy-3F

Marc Busqué a very good article 关于这个问题可能会有所帮助。

"When ActiveRecord encounters a foreign key violation, it raises an ActiveRecord::InvalidForeignKey exception. Even if in its documentation it just says that it is raised when a record cannot be inserted or updated because it references a non-existent record, the fact is that it is also used in the case we are interested."

有了它和 rescue_from 我们可以添加到 ApplicationController 或控制器关注点:

rescue_from 'ActiveRecord::InvalidForeignKey' do
  # Flash and render, render API json error... whatever
end

您是否偶然使用了 paranoia gem 或类似的东西?

如果你bidsparanoidauctions不是,你可能运行会出现这个错误。

这会发生,因为当 rails 执行 dependent: destroy 时,它会软删除出价,但它们实际上仍然存在于数据库中(它们只有 deleted_at 列放)。因此,外键约束将失败。

我的问题是我在尝试删除记录时使用了 @auction.delete(在我发布的屏幕截图中可见)。

删除将忽略我设置的任何回调。因此,即使我有一个 dependent destroy 子句,它也不会被调用 - 因此 Rails 会引发错误。 If/When 我将代码更改为 @auction.destroy,调用了回调并解决了问题。

参考: Difference between Destroy and Delete

Rails v4.2 你可以这样做:

创建迁移以更新外键

20160321165946_update_foreign_key.rb

class UpdateForeignKey < ActiveRecord::Migration
  def change
    # remove the old foreign_key
    remove_foreign_key :posts, :users

    # add the new foreign_key
    add_foreign_key :posts, :users, on_delete: :cascade
  end
end

其他的答案都不错,但是不要提有时候你想留下依赖记录,但是把外键作废

class Post < ActiveRecord::Base
  has_many :comments, dependent: :nullify
end

请注意,这将需要确保数据库中的外键列 table 具有空值:true

我不是肯定的,但你可能还需要添加 optional: true 到 dependent 中定义的 belongs to 关联型号。

一个非常简单的解释:关联的 table 包含至少 1 条记录,该记录与您要销毁的 table 中的记录相连。

要解决此问题,请添加 dependent: :destroy(假设用户 has_many 个帖子)

has_many :post, dependent: :destroy