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]
然后一切又开始工作了。
我正在将 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]
然后一切又开始工作了。