如何正确使用 `return` 进行 `render`:DoubleRenderError
How to properly use `return` for `render`: DoubleRenderError
我是 json 的新手,在返回时遇到了问题。我得到下面的错误,即使我到处都是 render
,我也 return
。是什么导致了这个错误?
AbstractController::DoubleRenderError in Api::V1::ArticlesController#show
Render and/or redirect were called multiple times in this action.
错误指的是下面def authenticate_user
中的render json: {errors: "not authorized" }, status: :unauthorized
。相反,我希望它只呈现 json 错误:"not authorized"。知道为什么这没有发生吗?
before_action :authenticate
def authenticate
unless authenticated?
render json: {errors: "not authorized" }, status: :unauthorized
return
end
end
这会调用以下辅助方法:
def authenticated?
!current_user.nil?
end
def current_user
token = request.headers["Authorization"]
email = request.headers["HTTP_USER_EMAIL"]
if token
user = User.friendly.find_by(email: email)
if user
if user.token_expired?
render json: {errors: "Session expired, please login" }, status: :unauthorized
return
elsif user.authenticated?(token)
@current_user = user
end
end
else
nil
end
end
更新: 为删除 return
提供的解决方案在任何地方都有效,但我不明白为什么。假设辅助方法如下所示。那么包含 return
就很重要了,对吧?因为否则,如果找不到@node,该方法仍将继续并且不会显示消息 "node not found" 。你能解释一下吗?
def create
@node = Node.find_by(id: params[:node_id])
if @node.nil?
render json: { errors: "node not found" }, status: :bad_request
return
end
nodee = @node.create(create_params)
if nodee.save
render json: @node, status: :created
else
render json: @node, status: :bad_request
end
end
换句话说,我原以为从 def authenticate
中删除 render
会导致 Rails 继续使用 create
方法,因为 def authenticate
没有告诉它去那里(我是这样看的 render
)。
Update2: 我也不能按照答案中的建议删除 render
,而是将其移至行首:return render json: {errors: "not authorized" }, status: :unauthorized
。很想知道这是为什么。
您的核心问题是 current_user
正在自己进行渲染 - 这是不寻常的,很容易意外渲染两次。第二件事是,如果在过滤器期间调用渲染或重定向,则前过滤器会停止处理操作:returning 从过滤器不会直接影响事物。
从 current_user
中删除 return 很大程度上是偶然的:这意味着 current_user
中的 return 值是渲染中的 return 值,即不再为零。这意味着 authenticated?
return 为真(即使用户未通过身份验证)因此您的之前过滤器不会再次呈现。 Rails 然后停止执行操作,因为渲染是从过滤器中调用的,所以看起来一切正常。
一般来说,虽然您确实需要调用 return 来停止方法的其余部分执行,但这显然不会停止调用方法内部的进程。
就我个人而言,我会保留 authenticate 不变,但更改 current_user 以便它没有任何副作用(设置 @current_user 除外)。如果您真的想更改错误消息,请在单独的实例变量中跟踪 current_user 为 nil 的原因(实际上我可能不会滚动我自己的身份验证,但这是另一回事)
对于未来的旅行者:
在 rails API 控制器中使用保护子句和辅助方法以避免多行 if else 链时,请执行以下操作:
- 将辅助方法重命名为 ?方法
- Return如果helper_methods? return是真的
- 在辅助方法中,确保return如果满足条件则为真
干杯
def controller_method
return if invalid_email?(params["user"]["email"])
...
def invalid_email?(email)
if EmailValidator.invalid?(email) then render(json: { status: 422, message: "Your email format is invalid. Please check that your email is correct and try again!" }, status: 422) and return true end
end
我是 json 的新手,在返回时遇到了问题。我得到下面的错误,即使我到处都是 render
,我也 return
。是什么导致了这个错误?
AbstractController::DoubleRenderError in Api::V1::ArticlesController#show
Render and/or redirect were called multiple times in this action.
错误指的是下面def authenticate_user
中的render json: {errors: "not authorized" }, status: :unauthorized
。相反,我希望它只呈现 json 错误:"not authorized"。知道为什么这没有发生吗?
before_action :authenticate
def authenticate
unless authenticated?
render json: {errors: "not authorized" }, status: :unauthorized
return
end
end
这会调用以下辅助方法:
def authenticated?
!current_user.nil?
end
def current_user
token = request.headers["Authorization"]
email = request.headers["HTTP_USER_EMAIL"]
if token
user = User.friendly.find_by(email: email)
if user
if user.token_expired?
render json: {errors: "Session expired, please login" }, status: :unauthorized
return
elsif user.authenticated?(token)
@current_user = user
end
end
else
nil
end
end
更新: 为删除 return
提供的解决方案在任何地方都有效,但我不明白为什么。假设辅助方法如下所示。那么包含 return
就很重要了,对吧?因为否则,如果找不到@node,该方法仍将继续并且不会显示消息 "node not found" 。你能解释一下吗?
def create
@node = Node.find_by(id: params[:node_id])
if @node.nil?
render json: { errors: "node not found" }, status: :bad_request
return
end
nodee = @node.create(create_params)
if nodee.save
render json: @node, status: :created
else
render json: @node, status: :bad_request
end
end
换句话说,我原以为从 def authenticate
中删除 render
会导致 Rails 继续使用 create
方法,因为 def authenticate
没有告诉它去那里(我是这样看的 render
)。
Update2: 我也不能按照答案中的建议删除 render
,而是将其移至行首:return render json: {errors: "not authorized" }, status: :unauthorized
。很想知道这是为什么。
您的核心问题是 current_user
正在自己进行渲染 - 这是不寻常的,很容易意外渲染两次。第二件事是,如果在过滤器期间调用渲染或重定向,则前过滤器会停止处理操作:returning 从过滤器不会直接影响事物。
从 current_user
中删除 return 很大程度上是偶然的:这意味着 current_user
中的 return 值是渲染中的 return 值,即不再为零。这意味着 authenticated?
return 为真(即使用户未通过身份验证)因此您的之前过滤器不会再次呈现。 Rails 然后停止执行操作,因为渲染是从过滤器中调用的,所以看起来一切正常。
一般来说,虽然您确实需要调用 return 来停止方法的其余部分执行,但这显然不会停止调用方法内部的进程。
就我个人而言,我会保留 authenticate 不变,但更改 current_user 以便它没有任何副作用(设置 @current_user 除外)。如果您真的想更改错误消息,请在单独的实例变量中跟踪 current_user 为 nil 的原因(实际上我可能不会滚动我自己的身份验证,但这是另一回事)
对于未来的旅行者:
在 rails API 控制器中使用保护子句和辅助方法以避免多行 if else 链时,请执行以下操作:
- 将辅助方法重命名为 ?方法
- Return如果helper_methods? return是真的
- 在辅助方法中,确保return如果满足条件则为真
干杯
def controller_method
return if invalid_email?(params["user"]["email"])
...
def invalid_email?(email)
if EmailValidator.invalid?(email) then render(json: { status: 422, message: "Your email format is invalid. Please check that your email is correct and try again!" }, status: 422) and return true end
end