【问题标题】:Callback before destroy and before associated records destroyed销毁之前和关联记录销毁之前的回调
【发布时间】:2012-07-25 16:08:22
【问题描述】:

我有以下型号:

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

我想设置一个观察者来在延迟作业队列中运行一个动作,这在大多数情况下都有效,但有一个例外。我希望 before_destroy 观察者在电话号码被销毁之前抓取与电话号码相关联的人,而延迟的工作实际上是在这些人身上起作用。

问题是,当一个电话号码被销毁时,它首先销毁:personal_phone_numbers记录,然后然后在它试图销毁电话号码时触发观察者。到那时,为时已晚。

有什么方法可以观察到依赖记录被删除之前的销毁动作?

【问题讨论】:

    标签: ruby-on-rails observers


    【解决方案1】:

    虽然这并不理想,但您可以从 personal_phone_numbers 关系中删除 :dependent =&gt; :destroy,并在对它们进行操作后在观察者中手动删除它们。

    但是,我认为这个问题可能会向您展示代码异味。你为什么要在电话号码的观察者中对人进行操作。听起来这种逻辑在连接模型中处理得更好。

    【讨论】:

    • 我的工作是观察连接模型。高级逻辑是关于查找重复帐户,并且查看所有形式的联系信息是该过程的一部分。这与其说是代码味道,不如说是“现实世界试图破坏数据库”的味道。
    【解决方案2】:

    使用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
    

    【讨论】:

    • 我的主要问题是我希望在观察者中使用它,因为它与电话号码不直接相关,并且在模型中包含此代码将更像是@cjhveal 提到的代码气味...(加上观察者观看了许多模型)
    • 我同意@DGM,但顺便说一句,可以破坏调用 super() 而不是 alias_method 方法?
    • @TJChambers 从多年前发现答案的乐趣! :) 是的,我认为 super 肯定是更好的方法。对于这样的事情,我不是观察者技术的忠实粉丝;我现在更喜欢有一个定义的地方(类方法?)来处理清理,而不是依靠自动捕获。
    【解决方案3】:

    听起来您的问题简而言之就是当PersonalPhoneNumber 被销毁时,您想要收集并处理Person 的集合。这种方法可能符合要求!

    以下是收集Person 模型的自定义回调示例。这里是一个实例方法,所以我们不必在 ActiveRecord 模型中实例化PersonalPhoneNumberCallbacks 对象。

    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 回调将传递模型,您可以对其数据进行操作。回调链完成后会被销毁。

    参考文献

    【讨论】:

      【解决方案4】:

      您可以在模型中使用 before_destroy 回调,然后在销毁父对象之前获取数据并执行您需要的任何操作。像这个例子这样的东西应该是你正在寻找的:

      class Example < ActiveRecord::Base
      before_destroy :execute_random_method
      
      
      private
      
      def execute_random_method
        ...
      end
      handle_asynchronously :execute_random_method
      

      【讨论】:

        【解决方案5】:

        有点老了,但我想我会分享一下 rails 现在为 before_destroy 回调提供了不错的 'prepend' 选项。这与 tomciopp had 遵循相同的思路,但允许您在类中的任何位置定义 before_destroy。

        before_destroy :find_associated_people, prepend: true
        
        def find_associated_people
          # using phone number, find people
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多