我在RoR中有一个简单的模型,我想留下人们进入网站的东西。但是,如果用户点击“删除”,我也希望能够隐藏一些内容。
所以我在模型中添加了一个名为“显示”的bolean属性。
我想知道,什么是最佳实践风格的方法。
我想我必须用以下内容更改控制器:
def destroy
@point = Point.find(params[:id])
@point.displayed = false
@point.save
respond_to do |format|
format.html { redirect_to points_url }
format.json { head :no_content }
end
但我不确定它是否干净。什么是最好的方法。
你猜我对RoR很吵。大块的代码将不胜感激。
谢谢
答案 0 :(得分:13)
自己实施(而不是使用宝石)。这比起初看起来要容易得多,并且它比那些改变 destroy
方法的含义要简单得多,这在我看来是个坏主意意见。
我并不是说使用宝石本身很复杂 - 我说通过改变destroy
方法的含义你改变了Rails世界中人们理所当然的含义 - 当你致电destroy
时,该记录将会消失,如果它们通过destroy
回调链接在一起,也可能会在依赖对象上调用dependent: destroy
。
更改destroy
的含义也很糟糕,因为在“约定优于配置”世界中,当您使用约定时,您实际上打破了Rails代码的“自动化”。你认为所有这些都是理所当然的,因为你读了一段Rails代码并且你知道某些假设通常适用 - 那些就是窗外的。当你以不明显的方式改变这些假设时,你几乎肯定会因此而引入一个错误。
不要误会我的意思,没有什么比实际阅读代码来检查你的假设更好了,但作为一个社区,能够谈论某些事情并且通常让他们的行为以某种方式行事也很好
请考虑以下事项:
destroy
动作,所以不要这样做。这是标准行动之一,但并不是必需的。update
操作设置和清除archived
布尔属性(或类似命名的内容)acts_as_paranoid
宝石,如果你需要为你的模型添加任何范围(除了宝石提供的范围),你会发现自己不得不破解它的方式,关闭默认的“隐藏存档记录”范围,当您遇到它时,它几乎立即失去其值。此外,这个宝石本身几乎没有任何东西,它的功能可以很容易地自己编写(我的意思是安装宝石本身的工作量几乎没有),所以从这个角度来看它实际上没什么好处。destroy
方法或操作是一个坏主意,因为它违反了Rails(和ActiveRecord)约定,即在对象上调用destroy
的含义。任何执行此操作的宝石(例如acts_as_paranoid
)也会打破这种惯例,并且你最终会让自己或其他人感到困惑,因为destroy
根本不会意味着它应该是什么意思。这会增加混乱,而不是代码的清晰度。不要这样做 - 你以后会付钱。before_destroy
回调并简单地返回false,这将阻止它被除非使用delete
的显式调用(无论如何都与destroy不同),否则将被销毁。此外,回调到位使得(a)非常明显为什么destroy
在不改变其含义的情况下不起作用,并且(b)很容易编写测试以确保它不可破坏。这意味着将来,如果您不小心删除了该回调或做了其他使该模型可销毁的内容,那么测试将失败,提醒您注意这种情况。答案 1 :(得分:11)
这样的事情:
class Point < ActiveRecord::Base
def archive
update_attribute!(:displayed, false)
end
end
然后在控制器的销毁操作中调用@point.archive
,您通常会调用@point.destroy
。您还可以创建default_scope
隐藏已归档的点,直到您明确查询它们为止,参见appling a default scope上的RoR指南。
编辑:根据normalocity&amp;更新我的答案logan的评论如下。
答案 2 :(得分:2)
看看acts_as_archive宝石。它将无缝地进行软删除。
答案 3 :(得分:2)
您的解决方案很好,但您可以使用acts_as_paranoid gem进行管理。
答案 4 :(得分:0)
在这种情况下,与其添加一个新的布尔标志,不如添加一个deleted_at:datetime
列
@point = Point.find(params[:id])
@point.touch(:deleted_at)
...
然后再
Point.where(deleted_at: nil) # these are NOT hidden
Point.where.not(deleted_at: nil) # these are hidden