Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In rails, How to determine if a record was destroyed by a dependent: :destroy callback?

I've got a record in my Rails app with an after_destroy hook that needs to do be aware why the record gets destroyed. More specifically, if the record is being destroyed in a cascade because its parent says dependent: :destroy, it needs to do things differently than if the record was individually destroyed.

What I tried to do is to see if its parent was destroyed?, only to figure out that dependent: :destroy callbacks are done before the parent is destroyed. Which makes sense because it should be able to fail. (i.e. restrict).

So, how do I do this?

like image 533
Pelle Avatar asked Feb 05 '14 13:02

Pelle


People also ask

What is dependent destroy in Rails?

Dependent is an option of Rails collection association declaration to cascade the delete action. The :destroy is to cause the associated object to also be destroyed when its owner is destroyed.

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.

How does Callback work in Rails?

Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.

What is around callback in Rails?

In Rails, callbacks are hooks provided by Active Record that allow methods to run before or after a create, update, or destroy action occurs to an object. Since it can be hard to remember all of them and what they do, here is a quick reference for all current Rails 5 Active Record callbacks.


1 Answers

Solution #1

If your model is simple enough and you don't need to invoke any callbacks in the child relation, you can just use dependent: delete_all in the parent.

Solution #2

For more complex scenarios you can use destroyed_by_association, which returns a ActiveRecord::Reflection::HasManyReflection object when it's part of cascade, or nil otherwise:

after_destroy :your_callback

def your_callback
  if destroyed_by_association
    # this is part of a cascade
  else
    # isolated deletion
  end
end

I just tried this in Rails 4.2 and it works.

Source: https://github.com/rails/rails/issues/12828#issuecomment-28142658

like image 195
alf Avatar answered Sep 19 '22 18:09

alf