我正在将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
但这会破坏版本控制的整个目的。我错过了什么吗?
答案 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
我认为就这些。