【问题标题】:How do I find out why I couldn't #destroy() a record?我如何找出为什么我不能#destroy() 记录?
【发布时间】:2013-05-27 06:23:37
【问题描述】:
person = Person.find(4123)
person.destroy #=> false

我有什么方法可以找出记录没有被删除的原因?该模型有两个验证,都仅在创建时触发。它有一个回调,但如果失败,回调不会阻塞。

我没有要查看的回溯或错误。

【问题讨论】:

  • 你在哪个 Rails 上?请发布您的 Person 模型。

标签: ruby-on-rails activerecord


【解决方案1】:

更新:请参阅 Mike Slate 的答案以获得更快的解决方案:https://stackoverflow.com/a/53872915/171183

我遇到了同样的问题,这就是我为弄清楚发生了什么所做的事情......

(TL;DR:底部给出的完整代码清单。)

首先,对于我要销毁的对象的类,我运行它以找出所有关联都设置为dependent: :destroy

ary = 
  <MyClass>.reflect_on_all_associations.select { |a| 
    a.options[:dependent] == :destroy 
  }.map(&:name)

然后我在我的对象上调用ary 中命名的每个关联并收集结果。这将关联名称限制为仅具有实际依赖对象的关联名称:

ary.select! { |association_name| 
  <my_object>.send(association_name).present? 
}

然后我可以尝试销毁这些关联名称返回的每个对象以找到问题对象:

associated_objects = 
  ary.each_with_object([]) { |association_name, acc| 
    acc.concat(<my_object>.send(association_name))
  }

problem_objects =
  associated_objects.select { |obj| obj.destroy; obj.errors.any? }
# ...

然后我可以查看每个问题对象的错误:

problem_objects.map(&:errors)

这就是我终于看到导致销毁失败的错误的地方。从那里开始,它是一个简单的编程问题 (SMOP) 来解决这个问题。

就我而言,有一个before_destroy 回调阻止destroy 处理我的一个依赖对象关联。为了让以后的调试更简单,我决定开始在 Rails 日志中记录失败回调的错误(除了将错误消息添加到 errors.base)。

完整的代码清单:

my_object = <your_object_here>

ary = 
  my_object.class.reflect_on_all_associations.select { |a| 
    a.options[:dependent] == :destroy 
  }.map(&:name)

ary.select! { |association_name| my_object.send(association_name).present? }

associated_objects = 
  ary.flat_map { |association_name| my_object.send(association_name) }

problem_objects =
  associated_objects.select { |obj| obj.destroy; obj.errors.any? }

problem_objects.map(&:errors)

【讨论】:

  • 谢谢,帮了我很多!在我的情况下,我只是在 before_destroy 方法中使用了 return false,它可以防止破坏对象。
  • 我对第二个代码块有点困惑。就像现在一样,它将选择ary 中的所有关联或不选择任何关联,具体取决于对象是否具有任何第一个关联。应该改为ary.select! { |a| obj.send(a).any? } 吗?
【解决方案2】:

我已经遇到过几次了,终于找到了一种简单的方法来确定记录没有被破坏的原因(在 Rails 5.x 中测试)。

只需将对 destroy! 的调用包装在一个救援块中,然后查看 error.record.errors。

begin
  person = Person.find(4123)
  person.destroy! #=> Note the exclamation mark which will cause an error if it fails
rescue ActiveRecord::RecordNotDestroyed => error
  puts "errors that prevented destruction: #{error.record.errors}"
end

【讨论】:

  • 我很惊讶这在person.destroy; person.errors 不起作用时起作用。很好的发现!
【解决方案3】:

此错误通常是由于在模型中的关联上指定了dependent: :restrict_with_error 而引发的。在您的模型定义(以及关联的模型定义)中快速搜索此内容,看看是否是这种情况。

【讨论】:

    【解决方案4】:

    您使用的是哪个版本的 Rails?在 Rails 4 中,您可以使用 person.destroy! 强制销毁。如果操作失败,将显示回溯。

    【讨论】:

    • 没错,这将引发 ActiveRecord::RecordNotDestroyed 异常
    • 没关系,但能否请您扩展您的问题以包括您的Person 模型?
    【解决方案5】:

    您应该添加一些调试信息,例如logger.debug 并查看您的日志文件。例如log/production.log 如果在生产模式等下运行,您应该能够找出原因。如果没有,您可以在此处发布相关的日志文件部分(例如您正在运行的操作),我们可以为您提供帮助。

    【讨论】:

    • 你会在哪里放置日志语句来捕获这个?
    【解决方案6】:

    现在有完全相同的错误。我没有得到任何回溯,因为这是一个逻辑错误。

    在我的例子中,我的模型在模型的关系中有一个冲突的dependent: destroy。这意味着我的模型想要删除之前已经删除的父模型。

    我认为这有点令人困惑,我将通过声明模型来说明:

    class Section < ApplicationRecord
      has_many :contents, dependent: :destroy
    
    class Content < ApplicationRecord
      belongs_to :section
      has_many :quizzes, dependent: :destroy
    
    class Quiz < ApplicationRecord
      belongs_to :content, dependent: :destroy
    

    我删除了section.destroy 部分并得到了错误。错误是Quiz-model 中关系:content 中的dependent: destroy,因为该内容已被截面模型中的dependent: destroy 删除。我希望这将有助于找到问题:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      • 2012-10-09
      • 2014-10-08
      • 2019-08-14
      相关资源
      最近更新 更多