Обратный вызов перед уничтожением и перед уничтожением связанных записей

У меня есть следующая модель:

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

Я хочу настроить наблюдателя для запуска действия в очереди delayed_job, которая работает по большей части, но с одним исключением. Я хочу, чтобы наблюдатель before_destroy захватил людей, связанных с телефонным номером, до того, как он будет уничтожен, и именно на этих людях действительно работает отложенная работа.

Проблема в том, что когда номер телефона уничтожается, он сначала уничтожает запись :personal_phone_numbers, а затем запускает наблюдатель, когда пытается уничтожить номер телефона. В этот момент уже слишком поздно.

Есть ли способ наблюдать за действием уничтожения до удаления зависимых записей?


person DGM    schedule 25.07.2012    source источник


Ответы (4)


Хотя это не идеально, вы можете удалить :dependent => :destroy из отношения personal_phone_numbers и удалить их вручную в наблюдателе после работы с ними.

Однако я думаю, что эта проблема может показывать вам запах кода. Почему вы оперируете людей наблюдателем по номеру телефона. Похоже, что эта логика лучше обрабатывается в модели соединения.

person cjhveal    schedule 06.08.2012
comment
Моя работа заключалась в том, чтобы наблюдать за моделью соединения. Логика высокого уровня заключается в поиске повторяющихся учетных записей, и просмотр всех форм контактной информации является частью этого процесса. Это не столько запах кода, сколько реальный мир пытается уничтожить запах базы данных. - person DGM; 07.08.2012

Использовать alias_method для перехвата вызова destroy?

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
person Joe Pym    schedule 06.08.2012
comment
Моя основная проблема заключается в том, что я хочу, чтобы это было в наблюдателе, потому что он не имеет прямого отношения к телефонным номерам, и наличие этого кода в модели было бы скорее запахом кода, который упоминает @cjhveal... (плюс наблюдатель наблюдает несколько моделей) - person DGM; 07.08.2012
comment
Я согласен с @DGM, но, кроме того, можно ли уничтожить вызов super (), а не подход alias_method? - person TJChambers; 03.11.2015
comment
@TJChambers радость открытия ответов многолетней давности! :) Да, я думаю, что супер, безусловно, был бы лучшим подходом. Я не большой поклонник техники наблюдателя в отношении подобных вещей; Теперь я бы предпочел иметь одно определенное место (метод класса?) для очистки, а не полагаться на автоматические уловы. - person Joe Pym; 04.11.2015

Похоже, ваша проблема в двух словах заключается в том, что вы хотите собрать и воздействовать на коллекцию Person, когда PersonalPhoneNumber будет уничтожен. Этот подход может отвечать всем требованиям!

Вот пример пользовательского обратного вызова для сбора Person моделей. Здесь это метод экземпляра, поэтому нам не нужно создавать экземпляр объекта PersonalPhoneNumberCallbacks в модели ActiveRecord.

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

Затем добавьте обратный вызов для вашей модели ActiveRecord:

class PersonalPhoneNumber < ActiveRecord::Base
  after_destroy PictureFileCallbacks
end

В вашем обратном вызове after_destroy будет передана модель, и вы сможете действовать на ее данных. После того, как цепочка обратного вызова будет завершена, она будет уничтожена.

Ссылки

person fdsaas    schedule 07.08.2012

Вы можете использовать обратный вызов before_destroy в модели, затем получить данные и выполнить любую операцию, которая вам нужна, прежде чем уничтожить родителя. Что-то вроде этого примера должно быть тем, что вы ищете:

class Example < ActiveRecord::Base
before_destroy :execute_random_method


private

def execute_random_method
  ...
end
handle_asynchronously :execute_random_method
person tomciopp    schedule 07.08.2012