Callback before destroy and before associated reco

2019-09-19 06:58发布

I have the following model:

class PhoneNumber < ActiveRecord::Base
  has_many :personal_phone_numbers, :dependent => :destroy
  has_many :people, :through => :personal_phone_numbers
end

I want to set up an observer to run an action in a delayed_job queue, which works for the most part, but with one exception. I want the before_destroy watcher to grab the people associated with the phone number, before it is destroyed, and it is on those people that the delayed job actually works.

The problem is, when a phone number is destroyed, it destroys the :personal_phone_numbers record first, and then triggers the observer when it attempts to destroy the phone number. At that point, it's too late.

Is there any way to observe the destroy action before dependent records are deleted?

4条回答
smile是对你的礼貌
2楼-- · 2019-09-19 07:33

While this isn't ideal, you could remove the :dependent => :destroy from the personal_phone_numbers relationship, and delete them manually in the observer after operating on them.

However, I think that this issue might be showing you a code smell. Why are you operating on people in an observer on phone number. It sounds like that logic is better handled in the join model.

查看更多
你好瞎i
3楼-- · 2019-09-19 07:36

Use alias_method to intercept the destroy call?

class PhoneNumber < ActiveRecord::Base
  has_many :personal_phone_numbers, :dependent => :destroy
  has_many :people, :through => :personal_phone_numbers

  alias_method :old_destroy, :destroy

  def destroy(*args)
    *do your stuff here*
    old_destroy(*args)
  end
end
查看更多
迷人小祖宗
4楼-- · 2019-09-19 07:38

You can use a before_destroy callback in the model, then grab the data and do whatever operation you need to before destroy the parent. Something like this example should be what you are looking for:

class Example < ActiveRecord::Base
before_destroy :execute_random_method


private

def execute_random_method
  ...
end
handle_asynchronously :execute_random_method
查看更多
乱世女痞
5楼-- · 2019-09-19 07:39

It sounds like your problem in a nutshell is that you want to gather and act on a collection of Person when a PersonalPhoneNumber is destroyed. This approach may fit the bill!

Here is an example of a custom callback to collect Person models. Here it's an instance method so we don't have to instantiate a PersonalPhoneNumberCallbacks object in the ActiveRecord model.

class PersonalPhoneNumberCallbacks
  def self.after_destroy(personal_phone_number)
    # Something like people = Person.find_by_personal_phone_number(personal_phone_number)
    # Delayed Job Stuff on people
  end
end

Next, add the callback do your ActiveRecord model:

class PersonalPhoneNumber < ActiveRecord::Base
  after_destroy PictureFileCallbacks
end

Your after_destroy callback will have the model passed down and you can act on its data. After the callback chain is complete, it will be destroyed.

References

查看更多
登录 后发表回答