Модульный подход к обработке ошибок в Rails.

Закон Мерфи:

Как гласит закон Мерфи, все, что может пойти не так, пойдет не так, поэтому важно быть к этому готовым. Это применимо везде, даже в разработке программного обеспечения. Приложение, которое мы разрабатываем, должно быть достаточно надежным, чтобы справиться с этим. Другими словами, он должен быть устойчивым. Это именно то, о чем этот пост в блоге.

Все, что может пойти не так, пойдет не так.

- Закон Мерфи

В типичном рабочем процессе Rails мы обрабатываем ошибки на уровне контроллера. Допустим, вы пишете API с помощью Rails. Рассмотрим следующий метод контроллера для визуализации пользовательского JSON.

Когда пользовательский объект найден, он отображает его как json, в противном случае отображает ошибку json. Это типичный способ написания метода show - это Rails. Но вот в чем загвоздка. Если запись пользователя не найдена, она не попадает в блок else, а отображает резервный контент 500.html. Что ж, это было неожиданно. Это связано с тем, что если запись не найдена, возникает ошибка RecordNotFound. То же самое и с find_by! или любые методы поиска на ура.

Исключение! = Ошибка

Прежде чем мы приступим к исправлению ошибок, нам нужно понять кое-что важное. Как видно из приведенного выше примера, мы получаем ошибку ActiveRecord :: RecordNotFound. Блок try catch в ruby ​​будет выглядеть примерно так, что отлично работает.

Но когда вы хотите спастись от всех исключений, действительно важно знать разницу между исключениями и ошибками в Ruby. Никогда не выполнять восстановление из исключений. Он пытается обработать каждое исключение, наследуемое от класса Exception, и в конечном итоге останавливает выполнение.

Вместо этого нам нужно спастись от StandardError. Вот отличное сообщение в блоге, объясняющее разницу http://blog.honeybadger.io/ruby-exception-vs-standarderror-whats-the-difference/.

Спасение

Для обработки ошибок мы можем использовать блок спасения. Блок восстановления аналогичен блоку try..catch, если вы из мира Java. Вот тот же пример со спасательным блоком.

При таком подходе ошибки устраняются в методах контроллера. Хотя это работает отлично, это может быть не лучший подход для обработки ошибок. Вот несколько причин рассмотреть альтернативный подход.

  1. Толстые контроллеры: обязательно прочтите эту отличную статью Thoughtbots https://robots.oughttbot.com/skinny-controllers-skinny-models.
  2. Принцип DRY: мы просто повторяем блокировку ошибки в разных местах, что противоречит принципу DRY (не повторяйся).
  3. Ремонтопригодность: сложнее поддерживать код. Изменения ошибки, такие как формат, повлекут за собой серьезные изменения.

Альтернативный подход - переместить блок обработки ошибок в ApplicationController. Более чистый подход - написать модуль обработчика ошибок.

Обработка ошибок - модульный подход

Чтобы обрабатывать ошибки в одном месте, наш первый вариант - написать в ApplicationController. Но лучше всего отделить его от логики приложения.

Давайте создадим модуль, который обрабатывает ошибки на глобальном уровне. Создайте модуль ErrorHandler (error_handler.rb) и поместите его в папку lib / error (или в другое место для загрузки), а затем включите его в наш ApplicationController.

Важно: загрузите модуль ошибок при запуске приложения, указав его в config / application.rb.

Примечание. Я использую несколько вспомогательных классов для рендеринга вывода json. Вы можете проверить это здесь.

Прежде чем приступить к работе с модулем error_handler, вот действительно интересная статья о модулях, которую вам обязательно стоит прочитать. Если вы заметили, что метод self.included в модуле работает так же, как если бы он был помещен в исходный класс. Поэтому все, что нам нужно сделать, это включить модуль ErrorHandler в ApplicationController.

Давайте проведем рефакторинг ErrorModule для размещения нескольких блоков обработки ошибок. Так он выглядит намного чище.

Если вы заметили ошибку ActiveRecord: RecordNotFound, она также наследует StandardError. Поскольку у нас есть механизм спасения, мы получаем: record_not_found. Блок StandardError действует как резервный механизм, который обрабатывает все ошибки.

Определите собственное исключение.

Мы также можем определить наши собственные классы ошибок, которые наследуются от StandardError. Для простоты мы можем создать класс CustomError, который содержит общие переменные и методы для всех определенных пользователем классов ошибок. Теперь наша UserDefinedError расширяет CustomError.

Мы можем переопределить методы, специфичные для каждой ошибки. Например, NotVisibleError расширяет CustomError. Как вы могли заметить, мы переопределяем error_message.

Для обработки всех ошибок, определенных пользователем, все, что нам нужно сделать, это спастись от CustomError. Мы также можем спастись от конкретной ошибки, если хотим обработать ее по-другому.

404 и 500

Вы можете обрабатывать распространенные исключения, такие как 404 и 500, хотя это полностью зависит от разработчика. Нам нужно создать для него отдельный класс контроллера, ErrorsController.

Скажите Rails использовать маршруты для разрешения исключений. Нам просто нужно добавить следующую строку в application.rb.

config.exceptions_app = routes

Теперь исключения 404 возвращаются к errors # not_found, а 500 - к errors # internal_server_error.

Заключительные примечания

Модульный подход - это способ обработки ошибок в Rails. Всякий раз, когда мы хотим изменить конкретное сообщение / формат об ошибке, нам просто нужно изменить его в одном месте. При таком подходе мы также отделяем логику приложения от обработки ошибок, тем самым делая Контроллеры Slick вместо Fat.

В Rails лучше всего использовать Skinny Controllers & Models .

Вот полный Исходный код для модульного подхода к обработке ошибок. Пожалуйста, нажмите кнопку "Рекомендовать", если вы сочли это полезным. И, как всегда, не стесняйтесь отвечать, если у вас есть сомнения. Ваше здоровье!