分享 像 PHP 的 die 方法一样终结 Rails 的 render

wwwicbd · 发布于 2017年08月09日 · 最后由 5long 回复于 2017年08月10日 · 419 次阅读
24195

场景是这样的:

Redis中用String型存了用户登录令牌, key是令牌, value是该用户的ID. 定义一个auth方法, 如果根据令牌能读到合法的用户ID, 就意味着该令牌有效而且能获取ID.(敏感权限再去数据库验证身份)

在一部分接口中需要登录才能操作, 所以希望一旦令牌非法, auth方法直接render错误码然后终结后续操作. 这个场景在PHP中可以用 die("err_info"); 来处理.

4-ways-to-early-return-from-a-rails-controller 这篇文章提到了几个实用方法, 利用返回值和return的组合. 但我想要的是一旦触发某个条件, 无论是在Controller还是在某个方法里, 立即render结果并终结后续操作.

方案

利用异常.

module DiyExceptions
  class RenderAndDie < StandardError
  end
end
class ApplicationController < ActionController::API
  # sth...

    # 类比PHP die()
  rescue_from DiyExceptions::RenderAndDie do |ex|
    msg = JSON(ex.message) rescue [1, "RenderAndDie"]
    resp = {
        code: msg[0],
        info: msg[1]
    }
    render json: resp
    logger.debug ">>>\n#{resp.to_json}<<<\n"
  end


  # 完全成功的请求
  # 直接结束请求
  def success(info)
    info = JSON.parse(info) rescue info if info.instance_of?(String)
    raise DiyExceptions::RenderAndDie, [0, info].to_json
  end


  # 业务上失败的请求, code > 0
  # 直接结束请求
  def failed(code, info)
    info = JSON.parse(info) rescue info if info.instance_of?(String)
    raise DiyExceptions::RenderAndDie, [code, info].to_json
  end

  # sth...
end

如此, 使用 failed 或 success 方法就可以啦 ;)

success "操作成功"

success [1,2,3]

success render_to_string json: {list: posts_list, total: posts_total}, include: {:user => {only: [:id, :name, :avatar]}}
共收到 5 条回复
15420

其实就是raise 然后在rescue_from 回这个异常并且做response的处理 和PHP die的关系是?

7072
if Rails.env.development?
      p ">>>"

用 logger 会好一些

logger.debug ">>>"

可以避免开发环境和其他环境行为不一样。

7386

我学ruby的原因就是不想再碰php,你居然让我噩梦重演

5c8fb2

我也是新手,想问下raise这个和这个一样吗

raise ::Unauthorized  XXX
rescue ActiveRecord::RecordNotFound
    render_404
end
A72675

对于这个应用场景我的意见是用现有框架里提供的 (before_action)[http://guides.rubyonrails.org/action_controller_overview.html] 来解决问题,而不是把其他语言 / 框架里你所熟悉的实现方法照搬过来。除非你有很好的理由。

@sefier 主楼的实现并没有完全还原 PHP die() 的语义,只是用异常做了个 goto 而已。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册