【问题标题】:How to properly use `return` for `render`: DoubleRenderError如何正确使用 `return` 进行 `render`:DoubleRenderError
【发布时间】:2016-04-30 20:07:33
【问题描述】:

我是 json 新手,返回时遇到问题。我得到下面的错误,即使我到处都是render,我也是return。是什么导致了这个错误?

Api::V1::ArticlesController#show 中的AbstractController::DoubleRenderError
在此操作中多次调用渲染和/或重定向。

错误是指下面def authenticate_user中的render json: {errors: "not authorized" }, status: :unauthorized。相反,我希望它只会呈现一个 json 错误:“未授权”。知道为什么这没有发生吗?

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,该方法仍将继续,并且不会显示消息“找不到节点”。你能解释一下吗?

  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。很想知道这是为什么。

【问题讨论】:

  • authenticate方法中移除return
  • 从您的authenticate 方法和current_user 方法中删除return
  • 谢谢,删除 render 有效。但我不明白。您能否看看添加到 OP 中的更新?

标签: ruby-on-rails ruby json ruby-on-rails-4 rendering


【解决方案1】:

您的核心问题是 current_user 正在自己进行渲染 - 这是不寻常的,并且很容易意外渲染两次。第二件事是,如果在过滤器期间调用渲染或重定向,则之前过滤器会停止处理操作:从过滤器返回不会直接影响事情。

删除current_user 的返回值很大程度上是偶然的:这意味着current_user 的返回值是render 的返回值,即不再是nil。这意味着 authenticated? 返回 true (即使用户未通过身份验证),因此您的 before 过滤器不会再次呈现。 Rails 然后停止执行该操作,因为从过滤器中调用了渲染,所以看起来一切正常。

虽然您确实需要调用 return 来停止其余方法的执行,但这显然不会停止调用方法内部的进程。

就我个人而言,我会保持原样进行身份验证,但更改 current_user 以使其没有任何副作用(设置 @current_user 除外)。如果您真的想更改错误消息,请在单独的实例变量中跟踪 current_user 为 nil 的原因(事实上,我可能不会滚动自己的身份验证,但那是另一回事了)

【讨论】:

  • 感谢您对理解和改进current_user 有很大帮助!
【解决方案2】:

对于未来的旅行者:

在 Rails API 控制器中使用保护子句和辅助方法以避免多行 if else 链时,请执行以下操作:

  1. 将帮助方法重命名为 ?方法
  2. 如果是 helper_methods 则返回?返回真
  3. 在辅助方法中,如果满足条件,请确保返回 true

干杯

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

【讨论】:

    猜你喜欢
    • 2020-03-28
    • 2019-10-20
    • 2013-09-20
    • 2023-02-05
    • 2017-08-29
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多