覆盖Rails ActiveRecord销毁行为的最佳方法是什么?

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

看来我至少有两个选择:

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

我错过了更好的方法吗?

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

选项2似乎有些Rails-ish但我想知道处理它的最佳方法。 我应该创建自己的inheritance自ActiveRecord :: Base的父类,重写那里的destroy方法,然后在我想要这种行为的模型中inheritance该类吗? 我是否还应该覆盖查找器行为,因此默认情况下不会返回标记为已删除的记录?

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

如果您实际上并不想再次查看这些记录,但只关心在销毁父项时子项仍然存在,则作业很简单:add :dependent => :nullify to has_many调用将对父项的引用设置为在销毁时自动为NULL ,并教导视图处理缺少的引用。 但是,这只有在您没有再看到该行的情况下才有效,即查看这些交易在公司名称下显示“[NO LONGER EXISTS]”。

如果你想再次看到这些数据,听起来你想要的与实际销毁记录无关,这意味着你永远不需要再次引用它们。 隐藏似乎是要走的路。

因为你实际上并没有破坏记录,所以你可以将你的行为放在一个触发标志的hide方法中,而不是像你建议的那样。

从那里,只要您想列出这些记录并且只包含可见记录,一个简单的解决方案是包含一个不包含隐藏记录的visible范围,并且当您想要再次找到该特定的隐藏记录时不包括它。 另一条路径是使用default_scope来隐藏隐藏的记录,并使用Model.with_exclusive_scope { find(id) }来提取隐藏的记录,但我建议不要使用它,因为它对于即将到来的开发人员来说可能是一个严重的问题,并且从根本上说更改Model.all返回的内容Model.all不反映方法调用建议的内容。

我理解让控制器看起来像Rails那样做的愿望,但是当你没有真正按照Rails的方式做事时,最好明确一点,特别是当它真的不那么痛苦的时候这样做。

我为这个确切的目的写了一个插件 ,称为偏执狂。 我从acts_as_paranoid “借用”了这个想法,并且基本上使用更少的代码重新编写了AAP。

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

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