Удаление активных записей рельсов с помощью delete_all / delete нарушает ограничение внешнего ключа - PullRequest
0 голосов
/ 31 января 2020

У меня есть активная ассоциация записи с параметром: зависимый =>: уничтожить, которая работает как задумано. Затем я обнаружил, что мне нужно использовать удаление вместо уничтожения из-за производительности, поэтому я просто изменил уничтожение на 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

, и это сработало для уничтожения, так что Я не так делаю?

Спасибо / Луиза

Ответы [ 2 ]

1 голос
/ 31 января 2020

В 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
0 голосов
/ 31 января 2020

Вам необходимо установить уровень миграции.

Примерно так:

create_table :childs do |t|
  t.references :parent, index: true, foreign_key: {on_delete: :cascade}
  t.string :name

  t.timestamps null: false
end
...