2

我正在使用 ActsAsTenant,并且在任何设计路线(即任何设计控制器)上都不断收到以下错误。似乎 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::Errors::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
4

4 回答 4

2

这是一篇旧帖子,但唯一一个询问这个确切问题的帖子,并且没有真正的解决方案。尝试在没有子域的情况下使用设计和acts_as_tenant 时出现错误。我想根据用户查找租户。这是我得到的错误:ActsAsTenant::Errors::NoTenantSet。

这里有解决方案,但这些对我不起作用。

我找到的解决方案是覆盖 Devise 用于扩展 User 模型的一些方法,以便这些方法使用 unscoped ,如此处所示。使用设计 4.6.2、acts_as_tenant 0.4.3、Rails 5.2.3

应用程序/模型/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/initializers/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
于 2019-05-05T15:52:19.943 回答
1

可以解决此问题,您可以在此错误报告中看到它:https ://github.com/ErwinM/acts_as_tenant/issues/49#issuecomment-77142527

于 2015-03-04T11:35:35.337 回答
0

好吧,不幸的是,我要做的是摆脱 Devise 并用 Clearance 替换它,这解决了第一轮问题,接下来我摆脱了 ActsAsTenant 并编写了我自己的小模块,其中包括设置默认范围并抛出一个如果没有设置租户,则会出错。总而言之,几个小时的工作,但现在一切都简单多了,所以值得

于 2014-07-30T06:37:25.020 回答
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
于 2019-11-06T22:15:47.020 回答