Consider the following code
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
When I request Users#show it renders {"error":"text"}
just fine.
But if I change unauthenticated
to
def unauthenticated(_error)
render json: { error: 'text' }, status: :unauthorized
end
And the resource responds with {"status":500,"error":"Internal Server Error"}
.
The stack trace:
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'
So calling render json: {}
in the handler causes the same error to be raised again. But at the same time render plain: ''
does not.
What happens when I change key from plain
to json
and how to make it respond with :unauthorized
instead of server error when using JSON?
I was using active_model_serializers library for rendering JSON.
It uses scope
option of render
as a method name to invoke and it is current_user
by default. So the library invoked current_user
method again when I called render json: ...
leading to the error.
I've changed unauthenticated
method to
def unauthenticated(_error)
render json: { error: 'text' }, status: :unauthorized, scope: nil
end
and it began to work as expected.