【问题标题】:What is the best way to override Rails ActiveRecord destroy behavior?覆盖 Rails ActiveRecord 破坏行为的最佳方法是什么?
【发布时间】:2010-11-21 03:03:16
【问题描述】:

我有一个应用程序,我想覆盖我的许多模型的破坏行为。用例是用户可能有删除特定记录的合法需求,但实际上从数据库中删除该行会破坏影响其他相关模型的引用完整性。例如,系统的用户可能想要删除他们不再与之有业务往来的客户,但需要维护与该客户的交易。

看来我至少有两个选择:

  1. 将数据复制到必要的模型中,有效地反规范化我的数据模型,以便删除的记录不会影响相关数据。
  2. 覆盖 ActiveRecord 的“销毁”行为,以设置一个指示用户“删除”记录的标志并使用此标志隐藏记录。

我错过了更好的方法吗?

选项 1 对我来说似乎是一个可怕的想法,尽管我很想听到相反的论点。

选项 2 看起来有点像 Rails,但我想知道处理它的最佳方法。我是否应该创建自己的从 ActiveRecord::Base 继承的父类,覆盖那里的 destroy 方法,然后在我想要这种行为的模型中从该类继承?我是否还应该覆盖查找器行为,以便默认情况下不返回标记为已删除的记录?

如果我这样做了,我将如何处理动态查找器?命名范围呢?

【问题讨论】:

    标签: ruby-on-rails ruby activerecord


    【解决方案1】:

    如果您实际上对再次查看这些记录并不感兴趣,而只关心在父级被销毁时子级仍然存在,那么工作很简单:将 :dependent => :nullify 添加到 has_many 调用以设置对销毁时自动成为NULL的父级,并教视图处理该引用丢失。但是,这仅在您可以不再看到该行的情况下才有效,即查看这些交易会在公司名称下显示“[NO LONGER EXISTS]”。

    如果您确实想再次查看该数据,听起来您想要的与实际销毁记录无关,这意味着您永远不需要再次参考他们。隐藏似乎是要走的路。

    而不是覆盖销毁,因为您实际上并没有销毁记录,所以将您的行为放在触发标志的hide 方法中似乎要简单得多,正如您所建议的那样。

    从那里开始,每当您想列出这些记录并且只包含可见记录时,一个简单的解决方案是包含一个不包含隐藏记录的visible 范围,并且在您想要查找特定记录时不包含它,再次隐藏记录。另一种方法是使用default_scope 隐藏隐藏记录并使用Model.with_exclusive_scope { find(id) } 拉出隐藏记录,但我建议不要这样做,因为这对于新来的开发人员来说可能是一个严重的问题,并且从根本上改变了@987654328 @ 返回根本不反映方法调用所暗示的内容。

    我理解希望让控制器看起来像他们正在以 Rails 方式做事的愿望,但是当您不是真正以 Rails 方式做事时,最好明确说明,尤其是当这样做真的没有那么痛苦的时候。

    【讨论】:

    • 谢谢Matchu。你是对的,我确实需要再次使用数据,所以 nullify 不是我想要的。虽然 Ryan 在他的回答中提到的插件的简单性很吸引人,但你关于行为明确的论点说服了我。感谢您的回复。
    【解决方案2】:

    我写了a plugin for this exact purpose,叫做偏执狂。我从acts_as_paranoid“借用”了这个想法,基本上用更少的代码重写了AAP。

    当您在记录上调用destroy 时,它实际上并没有删除它。相反,它会将您数据库中的deleted_at 列设置为当前时间。

    GitHub 页面上的 README 应该有助于安装和使用。如果不是,请告诉我,我会看看能否为您解决此问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-09
      • 2010-09-20
      • 1970-01-01
      • 2011-02-22
      • 2010-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多