如何破坏 Rails 应用程序和 return 404 为 JSON

How to break Rails application and return 404 as JSON

Rails 应用程序作为 API 服务工作。我使用 mongoid

在我现在写的控制器中:

class UsersController < ApplicationController
  def show
    @user = User.find params[:user_id]
    unless @user
      render json: { error: I18n.t('user.messages.not_found') }, status: :not_found
      return
    end
    # ... some actions with @user object 
  end
end

我需要使代码更简洁并将此代码移动到模块中。我假设控制器中的代码可能如下所示:

class UsersController < ApplicationController
  def show
    @user = User.find params[:user_id]
    not_found? @user

    # ... some actions with @user object
  end
end

或者像这样

class UsersController < ApplicationController
  def show
    @user = found? User, params[:user_id]

    # ... some actions with @user object
  end
end

Pundit gem (https://github.com/elabs/pundit) 就是一个例子。在我的控制器中我写:

...
def index
  authorize User, :index?
  @users = User.all
end
...

如果用户无法访问此页面,则 Pundit 会引发异常并 return 向带有 401 http 代码的客户端错误消息。

重构我的代码以使控制器更简洁的更好方法是什么?

我的解决方案:

lib/myapp/exceptions.rb

module MyApp
  module Exceptions
    class Error < StandardError; end
    class ModelNotFound < Error

      def initialize(model)
        # api_error - helper for create standart JSON-response
        @json = api_error("#{ model.model_name.plural }.#{ model.model_name.singular }_not_found")
        message = @json
        super(message)
      end

      def json
        @json
      end
    end

    def self.included(base)
      base.rescue_from MyApp::Exceptions::ModelNotFound do |e|
        render json: e.json, status: :not_found
      end
    end
  end
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base

  ...
  include MyApp::Exceptions

  def found?(model, id)
    @model = model.find id
    return @model if @model
    raise MyApp::Exceptions::ModelNotFound.new model
  end

使用示例:

app/controllers/users_controller.rb

class UsersController < ApplicationController
  def show
    @user = found? User, params[:user_id]

    # ... some actions with @user object
  end
end

当我执行 GET 请求时 /users/77777 应用程序 returns:

{
    'code': 'users_user_not_found',
    'error': 'User not found'
}