Hard cascade delete

class User < ActiveRecord::Base
  has_many: :invoices
  has_many: :components, through: :invoices
end

class Invoice < ActiveRecord::Base
  belongs_to: :user
  has_many: :omponents

  before_destroy :has_components, prepend: true

  def has_components
    if components.any? 
      errors[:base] << " - Nie wolno usuwać, gdyż ma składniki" 
      false
    end
  end

end

class Component < ActiveRecord::Base
  belongs_to: :invoice
end

w schema są oczywiście relacje i foreign_key

No i dobrze to działa, ale teraz zapragnąłem napisać metodę, która hardcorowo omija wszelkie sprawdzanie i kaskadowo usunie wszystko, gdy usuwam konto użytkownika

Próbowałem użyć
skip_callback ale wtedy wysypuje mi błąd ActiveRecord::RecordNotDestroyed i zgłasza problem ActiveRecord::Associations:HasManyAssociation

Co robię źle?

Dodam jeszcze, że gdy mam całkowicie usunięty wpis before_destroy :has_components, prepend: true

to z konsoli mogę spokojnie robić:

@user = User.find(cos)
@user.invoices.destroy_all

… a wtedy pięknie usuwa i wszystkie invoices i wszystkie powiązane components.

Pierwsze co przychodzi mi na myśl to:

dependent :delete_all

Ale nie wiem czy o to chodzi :smiley:

Faktycznie brzmi jak dependent: :destroy

A jak wtedy (gdy zastosuję dependent: :destroy) zabezpieczyć bazę przed usuwaniem, gdy invoices ma components? Czyli:

" - Nie wolno usuwać, gdyż ma składniki"

Dzięki za link ale to chyba nie rozwiązuje problemu.

Mam sytuację 1:
Korzystam z metody, która nie pozwala usuwać, gdy invoice ma components i wyświetla komunikat z ostrzeżeniem. I tak ma być.
Użytkownicy nie mają usuwać takich wpisów.

Sytuacja 2:
2) W chwili, gdy administrator usuwa konto Usera, chcę ominąć wszelkie walidacje i “siłowo” usunąć jego konto oraz wszystkie przypisane do niego invoices oraz zależne components

Do takiego specjalnego usuniecia dla admina, moglbys stworzyc osobna metode, ktora:

  • usunie rekordy poczynajac od tych ‘na dole’ relacji czyli components, a po nich invoices uzywajac delete_all (mogloby to sie nawet znalezc w czyms typu User#clear)
  • a na koniec usera zwyklym destroy

opakowujac te wywolania w jedna transakcje.

:smile:

Tak sądziłem, że nie uniknę tego

@user.invoices.each do | inv | 
  Component.where(invoice: inv).destroy_all

....

:frowning: