Изменение ключа «рендеринга» с «обычного» на «json» вызывает ошибку сервера

#ruby-on-rails #ruby-on-rails-6 #active-model-serializers

Вопрос:

Рассмотрим следующий код

 class AuthenticatedController < ApplicationController
  rescue_from InvalidCredentials, with: :unauthenticated

  def current_user
    raise InvalidCredentials
  end

  private

  def unauthenticated(_error)
    render plain: { error: 'text' }.to_json, status: :unauthorized
  end
end

class UsersController < AuthenticatedController
  def show
    render json: current_user
  end
end
 

Когда я запрашиваю пользователей#показать, он отображается {"error":"text"} просто отлично.

Но если я изменюсь unauthenticated на

   def unauthenticated(_error)
    render json: { error: 'text' }, status: :unauthorized
  end
 

И ресурс отвечает {"status":500,"error":"Internal Server Error"} тем же .

Трассировка стека:

 Started GET "/api/v1/user" for ::1 at 2021-08-25 12:24:30  0300
Processing by Api::V1::UsersController#show as JSON
  Parameters: {"user"=>{}}
Completed 500 Internal Server Error in 1ms (ActiveRecord: 0.0ms | Allocations: 214)

InvalidCredentials (InvalidCredentials):
app/controllers/users_controller.rb:in `show'
app/controllers/authenticated_controller.rb:in `current_user'
app/controllers/authenticated_controller.rb:in `unauthenticated'
 

Таким образом, вызов render json: {} обработчика приводит к повторению той же ошибки. Но в то же время render plain: '' этого не происходит.

Что происходит, когда я меняю ключ с plain на json и как заставить его реагировать :unauthorized вместо ошибки сервера при использовании JSON?

Комментарии:

1. Что там в stacktrace?

2. @AmitPatel Я добавил трассировку стека.

Ответ №1:

Я использовал библиотеку active_model_serializers для рендеринга JSON. Он использует scope опцию render в качестве имени метода для вызова, и это current_user по умолчанию. Поэтому библиотека current_user снова вызвала метод, когда я позвонил render json: ... , что привело к ошибке.

Я изменил unauthenticated метод на

   def unauthenticated(_error)
    render json: { error: 'text' }, status: :unauthorized, scope: nil
  end
 

и это начало работать, как и ожидалось.

Ответ №2:

Основываясь на предоставленной вами информации, проблема, скорее всего, заключается в том, как вы используете rescue_from Запрос, который вызывает ошибку, должен быть запросом JSON, чтобы это сработало. Например, если вы пытаетесь войти в систему из формы, обычно по умолчанию это HTML-запрос. Способ подтвердить это-использовать raise request.inspect метод контроллера. Если это так, то простого решения не существует, и вам придется исправить запрос самостоятельно или просто поддержать и то, и другое.