Подтвердить что ты не робот

Как узнать, почему я не смог #destroy() записать?

person = Person.find(4123)
person.destroy #=> false

Какие способы я могу выяснить, почему запись не была удалена? Модель имеет две проверки, оба триггера только для создания. Он имеет один обратный вызов, но обратный вызов не блокируется, если он терпит неудачу.

У меня нет следов или ошибок, чтобы посмотреть.

4b9b3361

Ответ 1

Обновление: см. ответ майка Слэйта для более быстрого решения: fooobar.com/questions/275397/....

Я столкнулся с той же проблемой, и вот что я сделал, чтобы выяснить, что происходит...

(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, не позволяющий разрушению работать с одной из моих зависимых объектных ассоциаций. Чтобы упростить отладку в будущем, я решил начать регистрировать ошибку в журнале 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)

Ответ 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

Ответ 3

Какую версию Rails вы используете? В Rails 4 вы можете принудительно уничтожить, используя person.destroy!. Если действие не выполнено, отображается трассировка.

Ответ 4

Эта ошибка обычно возникает из-за dependent: :restrict_with_error, указанной в ассоциации в модели. Запустите быстрый поиск этого в определении модели (а также связанные определения модели) и посмотрите, если это произойдет.

Ответ 5

Вы должны добавить некоторую отладочную информацию, например. logger.debug и посмотреть ваши файлы журналов. например log/production.log, если вы работаете в режиме производства и т.д., и вы должны быть в состоянии выяснить, почему. Если нет, вы можете опубликовать соответствующий раздел файла журнала (например, действие, которое вы выполняете) здесь, и мы можем вам помочь.