RoR - 不要破坏对象,只是标记为隐藏

Pau*_*ney 10 ruby-on-rails

我在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
Run Code Online (Sandbox Code Playgroud)

但我不确定它是否干净.什么是最好的方法.

正如你猜我对RoR的愚蠢.大块的代码将不胜感激.

谢谢

jef*_*unt 13

自己实现它(而不是使用gem).它比起初看起来要容易得多,并且它比那些改变destroy方法含义的任何宝石都要复杂,在我看来这是一个坏主意.

我并不是说使用宝石本身很复杂 - 我是说通过改变destroy方法的含义你改变了Rails世界中人们理所当然的东西的含义 - 当你打电话给destroy那条记录时要走了,并且destroy也许如果他们是通过链接在一起,也可以在相关对象称为dependent: destroy回调.

改变其含义destroy也是不好的,因为在"约定优于配置"世界中,当您使用约定时,您实际上打破了Rails代码的"自动化".你认为所有这些都是理所当然的,因为你阅读了一段Rails代码,而且你知道某些假设通常适用 - 那些会消失.当你以不明显的方式改变这些假设时,你几乎肯定会因此而引入一个错误.

不要误会我的意思,没有比实际阅读代码来检查你的假设更好的了,但作为一个社区,能够谈论某些事情并且通常让他们的行为以某种方式行事也是很好的.

考虑以下:

  • Rails中没有任何内容表明你必须destroy在控制器中实现该操作,所以不要这样做.这是标准行动之一,但并不是必需的.
  • 使用该update操作来设置和清除archived布尔属性(或类似名称的东西)
  • 我已经使用了acts_as_paranoidgem,如果你需要为你的模型添加任何范围(除了gem提供的范围),你会发现自己不得不破解它的方式,关闭默认的"隐藏存档记录"范围,当你遇到它,它几乎立即失去其价值.此外,这个宝石本身几乎没有任何东西,它的功能可以很容易地自己编写(我的意思是比安装宝石本身更多的工作),所以从这个角度使用它真的没有任何好处.
  • 如前所述,重写destroy方法或操作是一个坏主意,因为它违反了Rails(和ActiveRecord)约定,即调用destroy对象的意义.任何做这件事的宝石(acts_as_paranoid例如)也打破了这种惯例,你最终会混淆自己或其他人,因为destroy根本不会意味着它应该是什么意思.这会增加混乱,而不是代码的清晰度.不要这样做 - 你以后会付钱的.
  • 如果你想使用一个软删除宝石,因为你正在保护一些理论上未来的开发人员,他们可能会把你的数据搞得一团糟......那么,最好的解决办法就是不雇用或与这些人一起工作.缺乏经验的人需要指导,而不是防止他们犯错误的宝石.
  • 如果你真的,绝对必须防止破坏给定模型的记录(除了能够简单地归档它),然后使用before_destroy回调并简单地返回false,这将防止它被破坏,除非显式调用delete使用(无论如何都与破坏不同).此外,回调到位使得(a)非常明显为什么destroy在不改变其含义的情况下不起作用,以及(b)编写测试以确保它不可破坏是很容易的.这意味着将来,如果您不小心删除了该回调或执行了其他使该模型可销毁的内容,那么测试将失败,提醒您注意这种情况.


Noz*_*Noz 11

像这样的东西:

class Point < ActiveRecord::Base

  def archive        
    update_attribute!(:displayed, false)
  end 

end
Run Code Online (Sandbox Code Playgroud)

然后调用@point.archive你通常会调用的控制器的destroy动作@point.destroy.您还可以创建一个default_scope隐藏存档点,直到您明确查询它们为止,请参阅RoR指南,了解如何应用默认范围.

编辑:根据normalocity和logan的评论更新了我的答案.

  • 这改变了`destroy`的假设含义,这对随便读取控制器代码的人来说并不明显.`displayed`属性可以通过控制器中已经存在的`update`动作更新,就像任何其他字段一样.此外,`archivable`方法本质上作为常量运行,因为它需要更改代码才能更改此属性.因此,我不确定,如果你甚至想打开/关闭它,为什么在这种情况下方法会比常量更好. (2认同)