Devise Token Auth - versioned API: uninitialized constant ApplicationController

Devise Token Auth - versioned API: uninitialized constant ApplicationController

我正在将 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

当我尝试 POST:

{
    "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'

那也没用。

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

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).

唯一真正有效的是完全不将其限定在 namespace/module 中:

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

但这违背了版本控制的全部目的。我错过了什么吗?

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

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

。 . .我没有得到你在尝试类似解决方案时提到的 'different load error'。

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

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

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

以防万一有人在这里出现同样的错误。 @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

我想就这些了。

对我来说,我必须记住我的 user[email]user[password] 在通过 Postman 进行测试时必须更新到命名空间版本,例如my_v1_namespace_user[email] 然后一切又开始工作了。