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