How a child record knows when its parent is destroying? #12828

Closed
randoum opened this Issue Nov 10, 2013 · 6 comments

Projects

None yet

2 participants

@randoum
randoum commented Nov 10, 2013

Hi,

I got Parent model that has_many Child models (with dependent: :destroy).

The Child model perform actions on after_destroy. Now I am trying to don't perform those action when the destroy is triggered by the Parent record.

To achieve this I am checking the destroyed? method (which is the only way I found, but perhaps there is another way?)

It does not as I expected.

parent.rb

class Parent < ActiveRecord::Base
  has_many :children, dependent: :destroy, inverse_of: :parent
end

child.rb

class Child < ActiveRecord::Base
  belongs_to :parent, inverse_of: :children

  after_destroy :perform_some_actions

  private

  # This is the target action
  def perform_some_actions
    # It is to be called while destroying a Child record
    # But must not be called while destroying the parent record
    unless self.parent.destroyed?
      raise 'performing actions'
    end
  end
end

rspec test

require 'spec_helper'

describe 'testing' do
  it 'work as expected when destroying children' do
    parent = Parent.create name: 'parent'
    child = Child.create name: 'child', parent: parent

    # This test pass
    expect{ child.destroy }.to raise_error(RuntimeError, 'performing actions')
  end

  it 'does not work as expected when destroying parent' do
    parent = Parent.create name: 'parent'
    Child.create name: 'child', parent: parent

    # This test fails with the following message:
    # expected no Exception, got #<RuntimeError: performing actions>
    expect{ parent.destroy }.not_to raise_error
  end
end

It seems that the call backs are called in the following order:

  1. child.before_destroy
  2. child.after_destroy
  3. parent.before_destroy
  4. parent.after_destroy

The value of parent.destroyed? is false during steps 1, 2, and 3. And is true at step 4. Which makes sens, but does not answer to the following need: how a child record knows when his parent record is destroying

Note: I can provide a fully set-up example project upon request

Thanks for your help

@rafaelfranca
Member

If you don't want to run callbacks while deleting the parent so you should use :delete_all value for dependent option.

@randoum
randoum commented Nov 10, 2013

Sorry but that won't work

The child record need to activate its callbacks. In my specific case it is linked to paperclip attachment and delete or delete_all won't clean up attached files

The only thing that I need is to skip is one specific callback, not all of them

@rafaelfranca rafaelfranca reopened this Nov 10, 2013
@rafaelfranca
Member

Unfortunately there is no way to know if the parent is being destroyed in the before_destroy callbacks.

@randoum
randoum commented Nov 10, 2013

Would it be clever to have a ActiveRecord::Persistence::destroying? method, equivalent to destroyed? but that would be set to true at the very beginning of the destroy process?

@rafaelfranca
Member

Could you try destroyed_by_association?

@randoum
randoum commented Nov 10, 2013

So I changed my Child model like this:

  def perform_some_actions
    unless self.destroyed_by_association
      raise 'performing actions'
    end
  end

And all tests passed

Awesome! Many thanks for your time

@randoum randoum closed this Nov 10, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment