【问题标题】:How to design mutually dependent models with callbacks如何使用回调设计相互依赖的模型
【发布时间】:2014-06-30 12:51:29
【问题描述】:

所以我有两个模型AB

A 被保存或销毁时,B 需要根据A 发生的情况进行更新。

B 被保存或销毁时,A 需要根据B 发生的情况进行更新。

我不能只放 2 个回调,它会导致模型具有递归回调。当模型A 被保存为触发B 回调的结果时,我不需要触发回调,反之亦然。

rails 的方法是什么?

【问题讨论】:

    标签: ruby-on-rails activerecord model callback rails-activerecord


    【解决方案1】:

    我有类似的情况,你能做的最好的事情就是在你的回调中使用一个标志

    class A
      attr_accessor :is_updated_by_callback
      after_commit :update_b
    
      def update_b
        return if is_updated_by_callback
        b.is_updated_by_callback = true
        b.update
      end 
    end
    

    反之亦然

    【讨论】:

    • 丑吗?我不知道那是什么意思。也许随着过去 15 年框架的激增,我们倾向于忘记标志,但它通常很有用。玩得开心,并在您的宝石来源中搜索“flag”,您可能会感到惊讶。无论如何,如果您找到更好的解决方案,您会很乐意告诉我。
    • 例如,为了正确地做事,我必须在读取它的回调中重置标志,如果有多个消费者回调 - 它会变得复杂。我同意flag是很普通的东西。
    • 您不必重置标志,因为它没有保存在数据库中,感谢attr_accessor。如果你有多个回调可以同时触发,那么你可以使用按位标志而不是布尔值
    • 如果我想重用模型实例(同意这是一种罕见的情况,并且可能是一个糟糕的设计意图) - 我必须重置,因为否则我会得到不需要的回调跳过。
    • 我明白了。那么确实你需要一个更复杂的回调设计,因为 Rails 并不是为这种情况而设计的,正如你在 activesupport/lib/active_support/callbacks.rb#run_callbacks 中看到的那样。也许您可以使用 Kernel.caller 来验证该操作是否由回调触发 - 但这种技术进入了我对 ugly 的定义,因为我们依赖于将来可能会改变的 Rails 内部结构
    【解决方案2】:

    您可以在回调中使用update_columns

    例如:

    模型 A 已保存。在回调中,你有这样的东西:

    recordB.update_columns(:name => '')
    

    update_column 不会运行任何回调。 注意:它也不会运行验证,或更新 updated_at 字段。

    【讨论】:

    • 会工作,对,除非我需要验证和其他不相关的回调才能工作。所以没有更好的方法,我猜..
    猜你喜欢
    • 2013-05-29
    • 1970-01-01
    • 2013-03-26
    • 2018-05-28
    • 2014-10-15
    • 2016-04-06
    • 2019-05-29
    • 2011-01-25
    • 2013-04-06
    相关资源
    最近更新 更多