设计和代理不能很好地合作



我正在使用ActsAsTenant,并且我一直在任何设计路由(即任何设计控制器)上得到下面的错误。看起来,在设置租户之前,设计试图获取current_user或与获取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

我如何确保在设计开始寻找current_user之前设置租户?

ActsAsTenant::Errors::NoTenantSet at/editActsAsTenant::错误::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

这是一个旧的帖子,但唯一一个问这个确切的问题,没有真正的解决方案。当尝试使用没有子域的设计和acts_as_tenant时,我遇到了一个错误。我想根据用户查找租户。这是我得到的错误:ActsAsTenant::Errors::NoTenantSet.

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

我发现的解决方案是重写设计用于扩展User模型的一些方法,这样这些方法就可以使用无作用域的方法,如下所示。使用design4.6.2, acts_as_tenant 0.4.3, Rails 5.2.3

app/模型/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

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

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

你得到ActsAsTenant::Errors::NoTenantSet错误的原因,即使在改变你的ApplicationController使用prepend_before_action后,因为设计控制器被声明为

class DeviseController < Devise.parent_controller.constantize
...
prepend_before_action :assert_is_devise_resource!
...
end

父控制器是你的ApplicationController。当devicecontroller被实例化时,它首先运行ApplicationController中的所有代码,这些代码添加(放在回调链的当前前端)你的secure_app方法。只有在此之后,才能实例化子类(devicecontroller),并在其前面添加assert_is_device_resource !(现在把它放在你的secure_app方法之前)。

如果您希望在多个租户中使用相同的用户(电子邮件或您使用的任何唯一外部密钥),则上述无作用域的解决方案不起作用。你可以通过继承devicecontrollers来解决这个问题,这样你就可以添加你的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

相关内容

  • 没有找到相关文章

最新更新