Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What Does Rails Do With Both :dependent => :destroy and cascade delete/nullify/restrict

I'm trying to decide how best to set up (if at all) foreign key constraints for my rails application. I have a model Response that belongs_to a Prompt. I would like to use :dependent => :destroy to have destroy called on every Response that belongs to a deleted Prompt and I'm trying to decide what delete constraint I should place on my foreign key.

In short I want advice about how I can get best take advantage of both the destroy method on dependent objects and foreign key constraints to ensure cruft doesn't accumulate and reflect the logical structure of the data being stored. Several earlier questions such as Should I use ON DELETE CASCADE, :dependent => :destroy, or both? and Rails: delete cascade vs dependent destroy asked which was better but they don't really say much about how the two choices interact and in what order they are triggered or seemed vague on the point.

As I see it the considerations seem to break up into a few pieces:

  1. Does :dependent => :destroy call destroy first on the dependent objects before removing the parent from the database so destroy will still be called on these objects even if I use cascade delete?
  2. Does :dependent => :destroy remove the dependent objects from the database before (or in a transaction with) removing the parent from the database? In other words if I set cascade to nullify will the database end up wastefully nullifying the references on the child objects before they are deleted?

  3. Are deletes issued as a result of the original destroy and chained :dependent => :destroy options wrapped in a transaction or will unfortunately timed crashes leave cruft in the database if I don't set cascade delete?

  4. Finally will :dependent => :destroy ensure the parent object is deleted from the database if I use restrict as the foreign key on_delete option?
like image 898
Peter Gerdes Avatar asked Feb 15 '16 15:02

Peter Gerdes


People also ask

What is the difference between dependent => destroy and dependent => Delete_all in rails?

What is the difference between :dependent => :destroy and :dependent => :delete_all in Rails? There is no difference between the two; :dependent => :destroy and :dependent => :delete_all are semantically equivalent.

What is the difference between delete and destroy in rails?

Basically destroy runs any callbacks on the model while delete doesn't. Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can't be persisted). Returns the frozen instance.

What does dependent destroy mean rails?

If you set the :dependent option to: :destroy, when the object is destroyed, destroy will be called on its associated objects. :delete, when the object is destroyed, all its associated objects will be deleted directly from the database without calling their destroy method.

What does cascade delete do?

A foreign key with cascade delete means that if a record in the parent table is deleted, then the corresponding records in the child table will automatically be deleted. This is called a cascade delete in SQL Server.


1 Answers

With dependent: :destroy in a transaction rails first destroys all dependencies, and only then deletes the record itself.

There may be a race condition: if a dependent record was added just after rails read collection for destroying, but not deleted parent yet - it may be left over. Let's call these "race condition records" below.

  1. yes, you can use dependent: :destroy and on delete cascade, this way some children (race condition ones) can be deleted without callbacks. If callbacks are mandatory - on delete restrict together with some locking and explicit children deletion may be better. This is somewhat like validates :some_field, uniqueness: true that is better to be backed by unique index, only database itself can ensure data consistency.

  2. since parent is deleted last, on delete nullify will not get in the way (you'll get nullified race condition records)

  3. there's transaction wrapping all deletes, only race condition records can be left over

  4. on delete restrict over dependent: :destroy will trigger only for race condition records (and roll back whole transaction), but if there was no race condition - rails will happily delete everything.

like image 183
Vasfed Avatar answered Oct 23 '22 16:10

Vasfed