Devise Token Auth - 版本化API:未初始化的常量ApplicationController

时间:2016-07-24 20:35:39

标签: ruby-on-rails devise rails-api

我正在将Devise Token Auth集成到我的版本化 Rails 5 API中。结构如下:

的Gemfile

source 'https://rubygems.org'
...
gem 'omniauth', '~> 1.3'
gem 'devise_token_auth', '~> 0.1.38'
...

的routes.rb

require "api_constraints"

Rails.application.routes.draw do

  namespace :api, defaults: { format: :json } do
    scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
      mount_devise_token_auth_for 'User', at: 'auth'
      resources :users
    end
  end
end

application_controller.rb(app / controllers / api / v1 /)

module Api
  module V1
    class ApplicationController < ActionController::API
      include ActionController::Serialization
      include DeviseTokenAuth::Concerns::SetUserByToken
    end
  end
end

当我尝试发布时:

{
    "email": "testuser@domain.com",
    "password": "testuserpassword"
}

/api/auth/sign_in,我收到错误 ActionController::RoutingError (uninitialized constant ApplicationController)

devise_controller在尝试调用自己的方法时似乎无法访问ApplicationController。所以我尝试设置基本控制器:

mount_devise_token_auth_for 'User', at: 'auth', base_controller: 'Api::V1::ApplicationController'

那也没有用。

要解决此问题,我可以删除module中的application_controller.rb分隔以使其成为:

class ApplicationController < ActionController::API
    include ActionController::Serialization
    include DeviseTokenAuth::Concerns::SetUserByToken
end

但这当然会导致不同的加载错误(因为事情不再是正确的范围):LoadError (Unable to autoload constant Api::V1::ApplicationController, expected /home/ubuntu/workspace/app/controllers/api/v1/application_controller.rb to define it)

实际上唯一有效的方法是根本不在命名空间/模块中使用它:

Rails.application.routes.draw do

  mount_devise_token_auth_for 'User', at: 'auth'

  namespace :api, defaults: { format: :json } do
    scope module: :v1,
                  constraints: ApiConstraints.new(version: 1, default: true) do
      resources :users
    end
  end
end

但这会破坏版本控制的整个目的。我错过了什么吗?

3 个答案:

答案 0 :(得分:3)

我没有那种花哨的默认范围发生,但这对我有用:

Rails.application.routes.draw do
  namespace :api do
    scope :v1 do
      mount_devise_token_auth_for 'User', at: 'auth'
    end
  end
end

一个很大的区别是除了我的普通范围的ApplicationController之外,我在app/controller/application_controller.rb有一个ApplicationController:

class ApplicationController < ActionController::API
  include DeviseTokenAuth::Concerns::SetUserByToken
end

这可能不太理想,但它适用于DeviseTokenAuth目前的设计方式。正确的修复可能涉及DeviseTokenAuth本身内部的更改。

希望这很有帮助。通过上面的代码,我有以下路线可以完成我需要它做的事情:

api_user_session POST /api/v1/auth/sign_in(.:format) devise_token_auth/sessions#create

。 。 。当你尝试类似的解决方案时,我没有得到你提到的“不同的加载错误”。

答案 1 :(得分:0)

Devise尝试使其内置控制器继承自己的ApplicationController,但在您的应用中,该类不存在。相反,你有一个Api::V1::ApplicationController类。

幸运的是,您可以将Devise配置为继承其他内容。在config/initializers/devise.rb中,执行此操作:

config.parent_controller = 'Api::V1::ApplicationController'

答案 2 :(得分:0)

以防万一有人以相同的错误降落在这里。 @Ecnalyr的回答对我有很大帮助,但还远远不够,因为有时我的请求只会调用controllers/api/v1/application_controller.rb,有时只会调用controllers/application_controller.rb(以及与我的特定需求有关的其他特定原因)。

这就是我所做的:

# controllers/base_controller.rb
class BaseController < ActionController::API
  include DeviseTokenAuth::Concerns::SetUserByToken
  include ActionController::Serialization

  before_action :set_global_headers

  private

  def set_global_headers
    response.headers["Content-Type"] = "application/json"
    response.headers["X-Robots-Tag"] = "none"
  end
end

所以 BaseController 是我用于全局配置的交叉控制器。

# controllers/api/v1/application_controller.rb
module Api
  module V1
    class ApplicationController < BaseController
      include Api::V1::ResponseHelper # app/helpers/api/v1/response_helper.rb

      before_action :authenticate_api_v1_user!, except: [:new, :create]
      before_action :set_v1_headers

      private

      def set_v1_headers
        # Custom header specific to v1
      end
    end
  end
end

然后我将config.parent_controller = 'BaseController'添加到初始化程序中的devise.rb。

我的路线如下:

namespace :api do
  namespace :v1 do
    mount_devise_token_auth_for 'User', as: 'v1', at: 'auth', controllers: {
      token_validations:  'api/v1/users/token_validations',
      registrations:      'api/v1/users/registrations',
      passwords:          'api/v1/users/passwords',
      sessions:           'api/v1/users/sessions'
    }
  end
end

我在控制器中添加了Devise用户控制器,以防万一我必须对其进行编辑。

# controllers/api/v1/users/registrations_controller.rb
module Api
  module V1
    module Users
      class RegistrationsController < DeviseTokenAuth::RegistrationsController
        def create
          puts params # For debug
          super
          # Some action after registration
        end
      end
    end
  end
end

我认为就这些。