我正在使用ActsAsTenant,我在任何Devise路线(即任何Devise控制器)上都会收到以下错误。似乎Devise试图获取current_user或者在设置租户之前获取用户,因此ActsAsTenant会引发错误。我尝试使用prepend_before_action来设置租户但是没有用。
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
prepend_before_action :secure_app
before_action :authenticate_user!
private
def secure_app
self.class.set_current_tenant_by_subdomain_or_domain
end
end
如何在Devise开始寻找current_user之前确保租户已设置?
ActsAsTenant :: Errors :: NoTenantSet at / edit ActsAsTenant ::错误:: NoTenantSet
block in User.acts_as_tenant
() home/lee/.rvm/gems/ruby-2.1.1/bundler/gems/acts_as_tenant-1b7d146d750b/lib/acts_as_tenant/model_extensions.rb, line 54
block (3 levels) in User.build_default_scope
activerecord (4.1.4) lib/active_record/scoping/default.rb, line 103
User::ActiveRecord_Relation#scoping
activerecord (4.1.4) lib/active_record/relation.rb, line 285
block (2 levels) in User.build_default_scope
activerecord (4.1.4) lib/active_record/scoping/default.rb, line 103
block in User.build_default_scope
activerecord (4.1.4) lib/active_record/scoping/default.rb, line 102
User.evaluate_default_scope
activerecord (4.1.4) lib/active_record/scoping/default.rb, line 125
User.build_default_scope
activerecord (4.1.4) lib/active_record/scoping/default.rb, line 101
User.default_scoped
activerecord (4.1.4) lib/active_record/scoping/named.rb, line 33
User.all
activerecord (4.1.4) lib/active_record/scoping/named.rb, line 28
User.where
activerecord (4.1.4) lib/active_record/querying.rb, line 10
OrmAdapter::ActiveRecord#get
orm_adapter (0.5.0) lib/orm_adapter/adapters/active_record.rb, line 17
User.serialize_from_session
devise (3.2.4) lib/devise/models/authenticatable.rb, line 208
block (2 levels) in Warden::SessionSerializer#user_deserialize
devise (3.2.4) lib/devise.rb, line 462
Warden::SessionSerializer#fetch
warden (1.2.3) lib/warden/session_serializer.rb, line 34
Warden::Proxy#user
warden (1.2.3) lib/warden/proxy.rb, line 212
Warden::Proxy#_perform_authentication
warden (1.2.3) lib/warden/proxy.rb, line 318
Warden::Proxy#authenticate!
warden (1.2.3) lib/warden/proxy.rb, line 127
RegistrationsController#authenticate_user!
devise (3.2.4) lib/devise/controllers/helpers.rb, line 50
RegistrationsController#authenticate_scope!
devise (3.2.4) app/controllers/devise/registrations_controller.rb, line 124
block in ActiveSupport::Callbacks::Callback#make_lambda
activesupport (4.1.4) lib/active_support/callbacks.rb, line 424
block in ActiveSupport::Callbacks::Filters::Before.halting_and_conditional
activesupport (4.1.4) lib/active_support/callbacks.rb, line 143
RegistrationsController#run_callbacks
activesupport (4.1.4) lib/active_support/callbacks.rb, line 86
RegistrationsController#process_action
actionpack (4.1.4) lib/abstract_controller/callbacks.rb, line 19
RegistrationsController#process_action
actionpack (4.1.4) lib/action_controller/metal/rescue.rb, line 29
block in RegistrationsController#process_action
actionpack (4.1.4) lib/action_controller/metal/instrumentation.rb, line 31
答案 0 :(得分:1)
可以解决此问题,您可以在此错误报告中看到它:https://github.com/ErwinM/acts_as_tenant/issues/49#issuecomment-77142527
答案 1 :(得分:1)
这是一则古老的文章,但是唯一一个询问这个确切问题的文章,没有真正的解决方案。 尝试使用没有子域的devise和act_as_tenant时出现错误。我想根据用户查找租户。这是我得到的错误:ActsAsTenant :: Errors :: NoTenantSet。
有解决方案here,但这些解决方案对我不起作用。
我发现的解决方案是重写Devise用来扩展User模型的某些方法,以便这些方法使用不受作用域限制,如here所示。 使用装置4.6.2,acts_as_tenant 0.4.3,Rails 5.2.3
app / models / devise_overrides.rb
module DeviseOverrides
def find_for_authentication(conditions)
unscoped { super(conditions) }
end
def serialize_from_session(key, salt)
unscoped { super(key, salt) }
end
def send_reset_password_instructions(attributes={})
unscoped { super(attributes) }
end
def reset_password_by_token(attributes={})
unscoped { super(attributes) }
end
def find_recoverable_or_initialize_with_errors(required_attributes, attributes, error=:invalid)
unscoped { super(required_attributes, attributes, error) }
end
def send_confirmation_instructions(attributes={})
unscoped { super(attributes) }
end
def confirm_by_token(confirmation_token)
unscoped { super(confirmation_token) }
end
end
然后在app / models / user.rb中:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :invitable, :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :validatable
belongs_to :account
accepts_nested_attributes_for :account
acts_as_tenant(:account)
extend DeviseOverrides
end
现在,您可以添加config / intializers / acts_as_tenant.rb,一切将继续进行。
ActsAsTenant.configure do |config|
config.require_tenant = true
end
我的app / controllers / application_controller.rb看起来像这样:
class ApplicationController < ActionController::Base
set_current_tenant_through_filter
before_action :set_tenant
before_action :authenticate_user!
private
def set_tenant
current_account = current_user.account
set_current_tenant(current_account)
end
end
答案 2 :(得分:0)
不幸的是,我必须要做的就是摆脱Devise并用Clearance替换它,这解决了第一轮问题,然后我摆脱了ActsAsTenant并写了我自己的小模块,包括设置默认范围如果没有设置租户,则抛出错误。总而言之,工作几个小时,但现在一切都变得简单,所以非常值得。
答案 3 :(得分:0)
即使将ApplicationController更改为使用prepend_before_action后,您仍然收到ActsAsTenant :: Errors :: NoTenantSet错误的原因是,因为DeviseController被声明为
class DeviseController < Devise.parent_controller.constantize
...
prepend_before_action :assert_is_devise_resource!
...
end
父控制器是您的ApplicationController。实例化DeviseController时,它首先运行ApplicationController中的所有代码,这些代码会将您的secure_app方法添加(放置在回调链的当前位置)。只有在那之后,才能实例化子类(DeviseController),以该子类为assert_is_devise_resource!回调(现在将其放置在您的secure_app方法之前)。
如果您想在多个租户中拥有相同的用户(电子邮件或您使用的任何唯一外部密钥),则上述不受限制的解决方案将不起作用。您可以通过从DeviseControllers继承来解决此问题,以便可以在您的secure_app方法之前添加
。routes.rb
devise_for :users, only: %i[session], path: 'users',
path_names: {sign_in: 'login', sign_out: 'logout'},
controllers: {
sessions: 'users/sessions'
}
module Users
class SessionsController < Devise::SessionsController
# You can access secure_app because SessionsController inherits from your ApplicationController
prepend_before_action :secure_app
# GET /users/sign_in
def new
super
end
# DELETE /users/sign_out
def destroy
super
end
end
end