Чи можу я налаштувати видалення Cascade у Rails?


88

Я знаю, що це, можливо, десь в Інтернеті, але я не можу знайти відповідь тут, на Stackoverflow, тому я подумав, що можу трохи збільшити базу знань тут.

Я новачок у Ruby and Rails, але моя компанія вкладає в це досить значні кошти, тому я намагаюся познайомитися з цим трохи детальніше.

Мені було важко змінити своє мислення на розробку програми з "моделі", а не з бази даних, тому я намагаюся зрозуміти, як би виконувалася вся робота з дизайну, яку я класично виконував у Базі даних у Натомість модель рейок.

Отже, останнє завдання, яке я собі поставив, - з’ясувати, як налаштувати модель бази даних Rails для каскадного видалення? Чи є простий спосіб зробити це? Або мені доведеться зайти в MySql і налаштувати це?

Відповіді:


103

Ви також можете встановити: залежний параметр: delete_all. : delete_all видасть єдиний оператор SQL, щоб видалити всі дочірні записи. через це використання: delete_all може забезпечити вам кращу продуктивність.

has_many :memberships, dependent: :delete_all

8
Ваше пояснення бентежить. Буде використаний один оператор SQL, але метод знищення не буде викликаний для кожного дочірнього рядка. Для цього вам потрібно використовувати kill_all.
Джон Топлі

@John - сподіваюся, що редагування згладить плутанину. дякую, що вказали на це.
Mike Breen

26
Переконайтеся, що ви розумієте різницю між використанням :delete_allта :destroyдля цього. І те, і інше призведе до того, що дочірні членства (1 рівень для видалення [потрібне цитування] та nдля знищення (якщо їх діти мають залежні руйнування)) будуть видалені з бази даних, але створюватимуть :destroyекземпляри кожного дочірнього об’єкта та спочатку запускатимуть будь-які зворотні виклики, тоді :delete_allяк Оператор SQL DELETE у базі даних. :destroyчерез це повільніше, але це дозволяє мати зворотні дзвінки, коли запис знищується. Об’їзд Rails на одному кінці та створення інстанції n ^ x на іншому.
jstim

2
Я пропоную також налаштувати зовнішні ключі бази даних. Таким чином записи видаляються однією операцією. Дивіться відповідь нижче, яку я розмістив.
Хендрік

66

Так, можна, якщо ти використовуєш такі стосунки, як has_many, ти просто робиш це

has_many :memberships, dependent: :destroy

Ден, отже, моє наступне запитання - якщо я запустим команду db migrate, чи буде це насправді встановлено в db? Або каскад повністю оброблений рейками?
matt_dev

Так, це обробляється рейками. (Однак переконайтеся, що вам дійсно завжди потрібно видаляти всі пов'язані рядки.)
Stein G. Strindhaug

@Matt - рядок has_many повинен бути у вашому класі моделі, міграція не додасть цього для вас.
Гарет,

Я віддаю перевагу цьому рішенню, оскільки воно також працює, якщо залежна модель має інше відношення has_many
tpei

25

На відміну від наданої відповіді, я настійно рекомендую також робити це на рівні бази даних. Якщо у вас різні процеси або багатопотокове середовище, може статися, що записи неправильно видаляються. Крім того, зовнішній ключ бази даних пришвидшує процес видалення великої кількості даних.

Як у запропонованій відповіді, зробіть це:

has_many :memberships, dependent: :delete_all

Однак також переконайтеся, що встановили a foreign_keyв міграції. Таким чином база даних піклується про автоматичне видалення записів для вас.

Щоб звести нанівець значення при видаленні членства, якщо ви маєте модель користувача:

add_foreign_key :users, :memberships, on_delete: :nullify

Ви також можете видалити всі моделі, коли членство буде видалено

add_foreign_key :users, :memberships, on_delete: :cascade

Тож чи можу я використовувати як "has_many: членство, залежне:: delete_all", так і "add_foreign_key: users,: memberships, on_delete:: cascade"? Чи буде це добре працювати?
Рубікон

2
Вам навіть не потрібно буде налаштовувати delete_allмодель. Зовнішній ключ подбає про те, щоб видалити все належним чином для вас на рівні бази даних.
Хендрік

3
Мені цікаво, що відбувається, коли ти робиш обидва. Здається, це не повинно мати негативного ефекту, але чи мав хтось поганий досвід з такою практикою як AR, так і рівня DB?
James Klein

1
Рівень бази даних - це те, що я шукав. На мою думку, це має бути прийнятою відповіддю. Інші, здається, працюють лише в тому випадку, якщо мої запити дотримуються стандартних операцій ActiveRecord.
Бретт Бітті

10

Тільки майте на увазі, що delete_all не буде виконувати жодних зворотних викликів (наприклад, before_destroy і after_destroy) у дочірніх записах.


6

Схоже, цей плагін може дати вам те, що ви шукаєте, якщо ви хочете, щоб каскадне видалення відображалося у фактичній структурі бази даних:

http://www.redhillonrails.org/foreign_key_migrations.html

Формат використання цього в міграції буде приблизно таким:

create_table :orders do |t|
  t.column :customer_id, :integer, :on_delete => :set_null, :on_update => :cascade
  ...
end

5
Це посилання мертве, але це нова альтернатива: github.com/matthuhiggins/foreigner
gdelfino
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.