我有一个与:dependent =>:destroy的活动记录关联设置,可按预期工作。然后我发现由于性能原因我需要使用delete而不是destroy,因此我根据关联将只是将destroy更改为delete_all / delete。
当我尝试删除时:
shop.shop_snapshots.completed.last.delete
我收到错误消息:
ActiveRecord::InvalidForeignKey (PG::ForeignKeyViolation: ERROR: update or delete on table "shop_snapshots" violates foreign key constraint "fk_rails_c24b24adaf" on table "inventory_items"
但是为什么会这样-我相信我在快照上有正确的设置:
has_many :inventory_items, :dependent => :delete_all
它可以摧毁,所以我做错了什么?
谢谢/路易丝
在Postgres上,您可以在外键本身上使用CASCADE选项。
CASCADE指定在删除引用的行时,引用该行的行也应自动删除。
- https://www.postgresql.org/docs/9.5/ddl-constraints.html
这通常是在创建表时设置的,但是您可以通过删除然后重新添加外键约束将其添加到现有表中:
class AddCascadeToOrderItems < ActiveRecord::Migration[6.0]
def up
remove_foreign_key :order_items, :orders
add_foreign_key :order_items, :orders, on_delete: :cascade
end
def down
remove_foreign_key :order_items, :orders
add_foreign_key :order_items, :orders
end
end
由于这是在数据库级别处理的,因此模型中不需要配置。
has_many :inventory_items, dependent: :delete_all
它也可以正常工作,并且在像MySQL这样的农民数据库上是唯一的选择,但是只有在您调用.destroy
而不是.delete
在将关联声明为作为模型回调实现的模型上才会触发它。例如:
class Store < ApplicationRecord
has_many :inventory_items, dependent: :delete_all
end
store = Store.find(1)
store.destroy # triggers callbacks and will delete all assocatiated inventory_items
store.delete # will not trigger callbacks
好的,谢谢,您的回答对我有很大帮助。几个后续问题:a)在down方法中,remove和add方法应该正确切换吗?b)好的,我看到以下依赖项::delete_all如果我用destroy初始化它,则可以工作,但是它只能在“一个级别”上工作,即,可能不会删除任何order_items的子项,因为回调不会由on上的delete触发您要解释的order_items。因此,我将需要在外键上使用级联。
A)是的,您是对的-顺序错误。B)是的。也对 使用
.delete_all
仅创建单个SQL删除查询并且不实例化模型或调用回调的方法删除关联的记录。级联inte这种情况的优点是级联,因此如果正确设置外键,则子级和孙级将被删除。