Обратно извикване преди унищожаване и преди унищожаване на свързаните записи

Имам следния модел:

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 за прихващане на повикването за унищожаване?

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, но като настрана може да унищожи call 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