Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails在销毁所有时抛出RecordNotDestroyed异常_Ruby On Rails_Ruby_Activerecord - Fatal编程技术网

Ruby on rails Rails在销毁所有时抛出RecordNotDestroyed异常

Ruby on rails Rails在销毁所有时抛出RecordNotDestroyed异常,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,我有一个批处理工作程序,它通过清理一个表然后重新填充来遍历和更新数据库。应该防止数据库中的特定行被销毁,因此我在销毁之前有一个:dont\u destroy\u record回调,以确保我不删除特定记录 我遇到的问题是,active record在调用collection.destroy\u all,ActiveRecord:RecordNotDistromed时引发异常。每当:dont\u destroy\u record回调为这些特定记录返回false时,就会引发此错误 这个问题的两个解决方

我有一个批处理工作程序,它通过清理一个表然后重新填充来遍历和更新数据库。应该防止数据库中的特定行被销毁,因此我在销毁之前有一个
:dont\u destroy\u record
回调,以确保我不删除特定记录

我遇到的问题是,active record在调用
collection.destroy\u all
ActiveRecord:RecordNotDistromed
时引发异常。每当
:dont\u destroy\u record
回调为这些特定记录返回false时,就会引发此错误

这个问题的两个解决方案是包装
集合。在try catch中销毁\u all
,或者我可以循环调用每个对象上的
destroy
集合。这个问题还有其他可能的或更好的解决方案吗?一个限制是,我不能太多地更改这个批处理工作程序,因为它在许多其他项目中使用,并且需要是超级通用的


我觉得奇怪的是,
destroy\u all
会抛出该异常,因为它正在调用
destroy
。我在文档中也没有看到太多关于抛出异常的内容。

对这个问题有一些很好的评论,我想我会给出一个完整的答案,其中包括一些评论的要点,以及每种方法的代码示例和上/下分析

拯救 这样,您就可以将
destroy_all
分别展开到
destroy
每条记录。这将允许您检测在每条记录上何时引发异常,只需忽略异常并继续:

collection.each do |record|
  begin
    record.destroy
  rescue e => ActiveRecord:RecordNotDestroyed
    puts "Record #{record.id} not destroyed"
  end
end
缺点:


  • 有些人可能会发现这种未启蒙的红宝石,或者只是不好的做法
正面:

  • 这当然有效
  • 它通过了测试
销毁前使用验证功能过滤记录 如果您可以访问您的验证功能
dont\u destroy\u record
,则您可以预先测试集合并仅销毁通过集合的记录

safe_to_destroy = collection.select {|record| !record.dont_destroy_record }
safe_to_destroy.destroy_all
缺点:

  • 您的代码必须能够访问
    不销毁记录
    功能
  • 不要销毁记录
    不应有副作用
  • 这将使
    safe\u to\u destroy
    中的记录调用
    dont\u destroy\u record
    的次数增加一倍,因此可能会影响性能
  • 如果
    dont\u destroy\u record
    的结果在对给定记录的第一次和第二次调用之间可能发生变化(用户活动、后台进程等),则可能存在竞争条件
正面:

  • 根据上述条件,只能对可安全销毁的记录调用
    destroy\u all
改进查询以仅返回可销毁记录 这需要访问返回要销毁的
集合的查询。此查询将包含在验证函数中检查的相同条件

让我们假设这是无灵魂公司的一项任务,他们准备有选择地分离(解雇)至少工作30天的高薪员工,作为其每月清理流程的一部分。最初的查询可能如下所示:

collection = Person.joins(:employees).where(salary_level: :highly_compensated).where("person.hire_date < ?", DateTime.now - 30)
return false if role == boss && employees.any?
collection = Person.joins(:employees).where(salary_level: :highly_compensated).where("person.hire_date < ?", DateTime.now - 60).not(role: :boss).group(employee_id).having("COUNT(employees.id) = 0")
我们可以将其滚动到单个查询中,想象如下:

collection = Person.joins(:employees).where(salary_level: :highly_compensated).where("person.hire_date < ?", DateTime.now - 30)
return false if role == boss && employees.any?
collection = Person.joins(:employees).where(salary_level: :highly_compensated).where("person.hire_date < ?", DateTime.now - 60).not(role: :boss).group(employee_id).having("COUNT(employees.id) = 0")
collection=Person.joins(:employees).where(薪资水平:高薪酬).where(“Person.hire\u date<?”,DateTime.now-60).not(角色::boss).group(员工id).have(“COUNT(employees.id)=0”)
在我们想象的模型中使用这种方法,我们可以得到一个经过过滤的集合,然后我们可以安全地使用
destroy_all
。然后每个人都很高兴,除了那些非自愿参与无灵魂公司每月职业搬迁计划的员工

缺点:

  • 需要重新思考和测试查询
  • 需要访问权限才能更改查询
  • 需要保持查询逻辑与验证逻辑同步
正面:

  • 可以显著减少数据库查询开销
  • 调用destroy_all不需要显式的错误处理/避免机制
  • 你不是为没有灵魂的公司工作

在销毁
回调之前,您不需要在
中决定是否销毁某个内容,而是可以将初始集合筛选为您确实要销毁的集合,并且只销毁这些集合吗?不,因为筛选集合需要我更改批处理工作程序,而这将不起作用。您需要进行循环然后收集,因为这就是销毁所有正在做的。只需展开它;你甚至可以在循环中手动调用回调,比如,records.each{{{record}next if record.dont_destroy_record;record.destroy}或者你可以在循环中使用rescue(有些人认为rescue是缓慢的、懒惰的或糟糕的编程,这是他们的观点,伙计)如果你使用
destroy
而不是
destroy!
它不应该引起错误,因此你甚至不需要捕捉它-只需在该循环中留下一条注释,以便将来你知道它可能不会真的破坏它:)好吧,法院3日。大多数人都不赞成为“预期”建立一个援救条款“错误。你的记录数据集有多大?很好的总结!小错误,我会用
替换
不销毁记录(record).nil?
!!record.Don_destroy_record
-因为方法在记录上,所以不销毁记录,false.nil?==false:)“有些人可能会发现这是一个未启蒙的Ruby,或者只是一个坏习惯”->因为您正在拯救一个您希望看到抛出的异常;然而,根据其经典定义,救援应该是意想不到的