How do I find out why I couldn't #destroy() a record?

前端 未结 5 1156
陌清茗
陌清茗 2021-02-01 15:16
person = Person.find(4123)
person.destroy #=> false

What ways do I have to find out why the record wasn\'t deleted? The model has two validations, b

5条回答
  •  一整个雨季
    2021-02-01 15:25

    Update: See Mike Slate's answer for a quicker solution: https://stackoverflow.com/a/53872915/171183.

    I ran into this same issue and here's what I've done to figure out what's going on...

    (TL;DR: Complete code listing given at bottom.)

    First, for the class of the object I'm trying to destroy, I ran this to figure out what all associations are set as dependent: :destroy:

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

    Then I called each of the associations named in ary on my object and collected the results. This limits the association names to only those that actually have dependent objects:

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

    Then I can attempt to destroy each of the objects returned by these association names to find the problem object(s):

    associated_objects = 
      ary.each_with_object([]) { |association_name, acc| 
        acc.concat(.send(association_name))
      }
    
    problem_objects =
      associated_objects.select { |obj| obj.destroy; obj.errors.any? }
    # ...
    

    I then could look at the errors on each problem object:

    problem_objects.map(&:errors)
    

    And that's where I finally saw the error that was causing the destroy to fail. From there it was a Simple Matter Of Programming (SMOP) to fix the issue.

    In my case, there was a before_destroy callback preventing destroy from working on one of my dependent object associations. To make this simpler to debug in the future, I've decided to start logging an error to the Rails log on failed callbacks (in addition to adding the error message to errors.base).

    Complete code listing:

    my_object = 
    
    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)
    

提交回复
热议问题