Создание страницы ошибки для ошибки 422

В настоящее время я создаю динамические страницы ошибок для ошибок 500 и 404. Я хочу расширить это до 422 ошибок. Вот что мы имеем до сих пор.

config/application.rb

config.exceptions_app = self.routes

контроллеры/errors_controller.rb

class ErrorsController < ApplicationController
  def not_found
    render status: 404
  end

  def internal_server_error
    render status: 500
  end

  def unacceptable
    render status: 422
  end
end

маршруты.rb

get '/404' => 'errors#not_found'
get '/500' => 'errors#internal_server_error'
get '/422' => 'errors#unacceptable'

Страница public/422.html удалена. Страницы просмотра ошибок были созданы, но для краткости опущены. При возникновении ошибки 404 или 500 отображаются страницы ошибок. Однако, когда я получаю ошибку 422, я получаю следующую страницу ошибки.

введите здесь описание изображения

Я видел множество руководств, реализующих этот же подход, и он работает. Однако я получаю сгенерированную ошибку Rails, а не страницу ошибки, которую я создал. Что не так и как это исправить?

Учебники, которые я просмотрел:


person thank_you    schedule 10.01.2017    source источник
comment
Пробовали ли вы rescue_from?   -  person tadman    schedule 10.01.2017
comment
Ни в одном из учебников, которые я нашел, не используется rescue_from. Я опубликую ссылки на учебники, которые я просмотрел в своем вопросе.   -  person thank_you    schedule 10.01.2017
comment
Вот почему я связался с ним. Документация по Rails описывает это более подробно, чем большинство руководств.   -  person tadman    schedule 11.01.2017
comment
Да, я использовал rescue_from, и он работает безупречно. Я надеялся, что мне не придется использовать rescue_from в первую очередь. Ни в одном другом учебнике этот подход не упоминается, и если бы я мог избавиться от rescue_from и метода, который он вызывает, я бы упростил свой код.   -  person thank_you    schedule 11.01.2017
comment
Почему вы на это надеялись? Это инструмент для работы. Это самый простой способ выразить то, что вы хотите сделать. По умолчанию просто выйти из строя.   -  person tadman    schedule 11.01.2017
comment
У меня был другой комментарий разработчика, что config.exceptions_app = self.routes может быть проще выполнять свою работу и просто перенаправлять пользователя на страницу с ошибкой 422. Я исследовал и нашел эти статьи. Ни один из них не использует rescue_from, что заставило меня подумать, что должен быть другой способ сделать это. Но из того, что вы говорите, единственный путь к такому - через rescue_from.   -  person thank_you    schedule 11.01.2017
comment
Если у вас нет действительно убедительных аргументов, я думаю, что способ rescue_from — это наименее удивительный и наименее запутанный способ сделать это. Может быть, вы можете добавить сюда ответ, который объясняет ваше решение и ваши сомнения по поводу того, чтобы пойти по этому пути, чтобы другие могли лучше понять.   -  person tadman    schedule 11.01.2017
comment
Честно говоря, у меня нет веских аргументов. По какой-то причине эти учебники неверны или я упускаю что-то очевидное. rescue_from - правильный ответ. Я добавлю ответ через два дня, когда у меня будет возможность сделать это.   -  person thank_you    schedule 11.01.2017
comment
Они могут быть устаревшими. rescue_from не всегда рекламировался так хорошо, как следовало бы.   -  person tadman    schedule 11.01.2017
comment
@tadman, Спасибо за помощь.   -  person thank_you    schedule 11.01.2017


Ответы (1)


Я еще один разработчик, который работал над этим с @jason328. Оказалось, что это проблема, состоящая из нескольких частей, сначала с общими ошибками 422, а затем с конкретным сценарием, в котором Rails поднимал ActiveRecord::InvalidAuthenticityToken и не отображал соответствующую страницу.

1. Общие ошибки 422

Страница ошибки Rails

Мы временно избавились от этого в нашей локальной среде разработки, установив config.consider_all_requests_local = false. Но затем вместо нашей пользовательской страницы с ошибкой мы получили пустую белую страницу.

Пустая белая страница

В соответствии с этим вопросом о переполнении стека мы нужен match '/422', to: 'errors#unprocessable_entity', via: :all для маршрута вместо get '/422' => 'errors#unprocessable_entity'.

На данный момент общие ошибки 422 выполняются так, как должны. Мы настроили действие контроллера, которое поднимало ActiveRecord::InvalidAuthenticityToken, как только вы его нажимали, и отображало нашу пользовательскую страницу 422. Так что для тех, у кого просто есть проблемы с ошибками 422 в целом, вышеизложенное должно помочь вам.

2. Недействительный токен подлинности

Но поскольку распространенной причиной ошибок 422 на самом деле является получение ошибки InvalidAuthenticityToken в дикой природе, кажется, стоит описать остальную часть проблемы, с которой мы столкнулись. В реальном сценарии, когда приложение генерировало собственную ошибку InvalidAuthenticityToken, теперь мы получали только текстовую ошибку 500 вместо нашей пользовательской страницы 422.

Только текст 500 ошибка

Мы смогли отследить это до FAILSAFE_RESPONSE в ActionDispatch::ShowExceptions#render_exception. Именно здесь Rails берет сгенерированное исключение и преобразует его в массив ответов [status, body, headers]. Если в это время возникает другое исключение, а не попадание в бесконечный цикл, оно сдается и возвращает FAILSAFE_RESPONSE. В этом случае при составлении ответа возникла еще одна ошибка InvalidAuthenticityToken.

В этот момент пришло время для стратегии :rescue_from:

rescue_from ActionController::InvalidAuthenticityToken,
            with: :rescue_invalid_authenticity_token

def rescue_invalid_authenticity_token
  #...notify services as if this error weren't being rescued

  redirect_to '/422'
end

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

person arthurlewis    schedule 13.01.2017