简体   繁体   中英

Changing "render" key from "plain" to "json" causes server error

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.

Based on the information you have given, the problem is most likely how you use rescue_from The request which triggers the error have to be a JSON request in order for this to work. For example if you try to login from a form it's usually by default a HTMl request. A way to confirm this is to use raise request.inspect in the controller method. If this is the case, there is no easy fix and you will have to fix the request it self or just support both.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM