[Rails] Exception handling #2
В одной из своих заметок я рассказывал о том, как правильно отдавать ошибки и статусы для запросов в разных форматах. Недавно наткнулся на небольшое дополнение, оно давно уже не ново, но для общего развития будет полезно.
В ранней статье не описывалась обработка ошибки авторизации. Если пользователь пытается войти без токена, то внутри модуля с этой проверкой, происходит возврат статуса //403// без каких либо дополнительных сообщений:
module ApiHelper
def require_auth
head :forbidden unless current_client
end
def current_client
@client ||= Client.find_by_api_token(params[:api_token])
end
end
Но вместе с ним в заголовках вернется и Content-Type
, который не всегда должен быть markdown/html.
Content-Type: markdown/html; charset=utf-8\r\nStatus: 403 Forbidden
Это сломает вашего клиента, который к примеру написан с использованием Weary.
Правильный способ
Есть хорошая статья, в которой говорится, что лучше всего рассказывать пользователю о том, что он неправ через исключения. Т.е. наилучшим сигналом будет не запись в лог проблем, а именно бросание исключения. Логи далеко не все читают, а из тех, кто читает - умеющих его нормально разбирать и понимать очень и очень мало.
Переделаем немного наш модуль:
def require_auth
raise ApplicationController::Forbidden unless current_client
end
В главном ApplicationController
пропишем
class ApplicationController < ActionController::Base
class Forbidden < StandardError; end
end
в config/application.rb
добавляем:
config.action_dispatch.rescue_responses.merge!(
'ApplicationController::Forbidden' => :forbidden
)
routes.rb
:
match "/403" => "errors#forbidden"
Добавляем написанный в предыдущей заметке errors_controller
метод forbidden
def forbidden
@body_msg = "Access Denied"
render status: :forbidden
end
Далее добавляем вью с нужным нам форматом вывода и после запроса получаем:
Content-Type: application/json; charset=utf-8\r\nStatus: 403 Forbidden
{ "message": "Access Denied" }
То, что нужно! Таким образом можно обработать любую исключительную ситуацию и возвращать разные сообщения и статусы в нужных местах. Просто добавьте исключение, обработчик и пропишите в роутах и application.rb
нужное исключение, создайте вью с правильным форматом ответа и радуйтесь жизни)
UPD: в комментариях добавили про 4ые рельсы и матч, вношу поправку, если вы пишите на 4х, то в роутах должно быть:
routes.rb
:
match "/403" => "errors#forbidden", via: :get