Devise и ActsAsTenant не очень хорошо играют вместе

Я использую ActsAsTenant, и я продолжаю получать ошибку ниже на любом маршруте Devise (то есть любом контроллере Devise). Похоже, что Devise пытается получить 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

Как мне убедиться, что клиент настроен до того, как 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

2 ответа

Решение

Хорошо, к сожалению, мне пришлось избавиться от Devise и заменить его на Clearance, что решило первый раунд проблем, затем я избавился от ActsAsTenant и написал свой собственный маленький модуль, который при включении устанавливает область по умолчанию и выдает ошибка, если арендатор не установлен. Всего пара часов работы, но теперь все намного проще, так что оно того стоит

Это старый пост, но единственный, который спрашивает об этой конкретной проблеме, и нет реального решения. Я получаю сообщение об ошибке при попытке использовать devise и acts_as_tenant без поддоменов. Я хотел найти арендатора на основе пользователя. Это ошибка, которую я получаю: ActsAsTenant::Errors::NoTenantSet.

Здесь есть решения, но они не работают для меня.

Решение, которое я нашел, состояло в том, чтобы переопределить некоторые методы, которые Devise использует для расширения модели User, чтобы эти методы использовали unscoped, как показано здесь. Использование devise 4.6.2, actions_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/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

Это можно обойти, вы можете увидеть это в отчете об ошибке: https://github.com/ErwinM/acts_as_tenant/issues/49

Причина, по которой вы получаете ошибку ActsAsTenant::Errors::NoTenantSet даже после изменения вашего ApplicationController на использование prepend_before_action, заключается в том, что 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
Другие вопросы по тегам