我有一个应用程序,我希望覆盖许多模型的destroy行为。用例是用户可能有合法需要删除特定记录,但实际上从数据库中删除该行会破坏影响其他相关模型的参照完整性。例如,系统用户可能希望删除与他们不再开展业务的客户,但需要维护与该客户的交易。
似乎我至少有两个选择:
我错过了更好的方法吗?
选项1对我来说似乎是一个可怕的想法,尽管我喜欢听到相反的论点。
选项2似乎有些Rails-ish但我想知道处理它的最佳方法。我应该创建自己的继承自ActiveRecord :: Base的父类,重写那里的destroy方法,然后从我想要这种行为的模型中继承该类吗?我是否还应该覆盖查找器行为,因此默认情况下不会返回标记为已删除的记录?
如果我这样做,我将如何处理动态查找器?如何命名范围?
答案 0 :(得分:8)
如果您实际上并不想再次查看这些记录,但只关心在销毁父级时孩子仍然存在,那么工作很简单:将:dependent => :nullify
添加到has_many
来电在销毁时自动将对父级的引用设置为NULL
,并教导视图处理缺少的引用。但是,这只有在您没有再看到该行的情况下才有效,即查看这些交易在公司名称下显示“[NO LONGER EXISTS]”。
如果你做想再次看到这些数据,听起来就像你想要的那样与实际销毁记录无关,这意味着你永远不需要再次提到他们。隐藏似乎是要走的路。
而不是覆盖destroy,因为你实际上并没有破坏记录,所以将你的行为放在触发标志的hide
方法中似乎要简单得多,如你所建议的那样。
从那里,只要你想列出这些记录并且只包含可见记录,一个简单的解决方案是包含一个不包含隐藏记录的visible
范围,当你想要找到它时不包括它具体的,隐藏的记录。另一条路径是使用default_scope
来隐藏隐藏的记录并使用Model.with_exclusive_scope { find(id) }
来提取隐藏的记录,但我建议不要使用它,因为它对于即将到来的开发人员来说可能是一个严重的问题,并且从根本上来说更改Model.all
返回的内容根本不会反映方法调用建议的内容。
我理解让控制器看起来像是按照Rails的方式做事的愿望,但当你不是真的按照Rails的方式做事时,最好明确一下,特别是当它真的没那么痛苦的时候。
答案 1 :(得分:6)
我写了a plugin for this exact purpose,称为偏执狂。我从acts_as_paranoid“借用”了这个想法,并且基本上使用更少的代码重新编写了AAP。
当您在记录上调用destroy
时,它实际上并未将其删除。相反,它会将数据库中的deleted_at
列设置为当前时间。
GitHub页面上的README应该对安装有帮助。用法。如果不是,请告诉我,我会看看能否为您解决这个问题。