【问题标题】:Ordering of callbacks in ActiveRecordActiveRecord 中的回调排序
【发布时间】:2019-06-22 13:52:44
【问题描述】:

我在 ActiveRecord 中排序回调时遇到了一些问题。根据 Rails guides,创建对象时回调的顺序如下:

  • before_validation
  • after_validation
  • before_save
  • around_save
  • before_create
  • around_create
  • after_create
  • after_save
  • after_commit/after_rollback

我的模型中有两个回调。一个用于 after_save(在创建和更新时运行),第二个用于 after_create。在创建时,我希望仅在 after_save 回调之后运行 after_create 回调。如何在 ActiveRecord 中完成这项工作?谢谢。

【问题讨论】:

  • 好吧,你不能重新排序回调。因此,要么将您的逻辑放入after_save(或更高版本),要么完全放弃使用回调。例如,支持某种 Builder 模式。
  • 由于rails-3rails-5 应用程序升级,我没有看到任何这样做的目的。因此,@SergioTulentsev 建议的更改是有效且可取的。
  • @SergioTulentsev 如何将after_create 逻辑添加到after_save 中? after_save 也将在更新时运行。
  • @BKS: 顶一下,你可以在before_create 中设置一个标志。像self.record_was_just_created = true 这样的东西。然后在after_save 中检查这个标志。如果标志为真,则运行特定于创建的部分。我,我会将其提取到单独的构建器/更新对象中。应该使构建过程显而易见。并且可以在需要时避免。
  • @BKS 您可以使用 new_record? 检查记录是否为新记录。所以在 after_save 回调检查self.new_record?

标签: ruby-on-rails activerecord


【解决方案1】:

不要更改 rails 的行为call_backs - 即使您知道如何操作,以后在应用程序上工作也会变得更加困难 - 更改放置代码的位置。

你对call_backs 的名字太执着了。什么时候跑更重要。

以下是我们对您的设计的了解,而无需假设哪些是实现它的最佳方式...

  • 您有一个在创建新记录后运行的方法
  • 您有一个在旧记录更新后运行的方法

您似乎可以在此处更改设计决策以简化编程 - 但这样做会破坏最佳实践...

  • 出于某种原因,您认为更新方法应该每次都运行 (after_save) 而不是 after_update)
  • 出于某种原因,您认为创建方法应该在更新方法之后运行(这是不健康的代码链)

从技术上讲,创建和更新所需的部分应该分成第三种方法,并由after_createafter_update 调用,以便您的代码自己记录并且更易于理解。

所有这些都是相对重要的——因为大多数有经验的程序员都强调你应该只在没有其他方法是合理的时候才使用call_backs——因为他们在解决晦涩难懂的问题时很难概念化。


解决方案 1 - Rails 方式

after_save 应该只用于需要同时运行更新和创建的代码。任何需要为其中一个或另一个运行的代码都应分解为更小的方法,然后根据需要由after_updateafter_create 调用以使其保持干燥。

解决方案 2 和 3 在不改变设计的情况下重构旧代码

  1. 设置工作测试以确保您的代码在您期望的地方失败并成功
  2. after_save 必须运行 - 所以我们知道它必须在那里。我们将它包装在一个名为 'update_method_code' 的方法中来封装它。
  3. 将“update_method_code”的方法定义移动到模型或服务对象的某个位置。
  4. after_save 中保留对“update_method_code”的方法调用。

由于我们在技术上没有改变任何东西,所以测试应该是绿色的。

  1. 您之前在 after_create 中编码 - 将其包装在名为“new_object_code”的方法中,以便对其进行封装。
  2. 将“new_object_code”的方法定义移动到模型或服务对象的某个位置。

这是你有几个选择的地方......

  • 您可以使用以下四种方法之一进行“update_method_code”测试 activerecord lifecycle checks 测试调用方法 'new_object_code'。这不好,因为它会产生可见性问题 并且意味着如果一个失败,其余的都会失败。以一种非常严厉的方式 确保您的“new_object_code”条件仅在之后运行 'update_method_code'

  • 您使用已构建的 Rails 方法。 after_save :update_method_code on: :create 触发“update_method_code”。请参阅此处的示例Rails Guide for transactions。请记住,即使您的其他 after_save 调用没有运行,这也可能会运行......所以再一次,这种方法不如简单地遵循 Rails 方式和使用 after_update / after_create 健全。


祝你的项目好运!

【讨论】:

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