TL; DR: в мультитенантном приложении с Devise пользователь должен иметь возможность зарегистрироваться с одним и тем же адресом электронной почты для разных арендаторов / учетных записей. Как я могу заставить Devise использовать account_id в User.find_for_database_authentication
?
У меня мультитенантное приложение. Каждый поддомен принадлежит учетной записи со многими пользователями и администраторами (разные таблицы, нет наследования между ними).
class User < ApplicationRecord
belongs_to :account
devise :database_authenticatable, :confirmable, :recoverable, :rememberable
validates :email, uniqueness: true
end
class AdminUser < ApplicationRecord
belongs_to :account
devise :database_authenticatable, :confirmable, :recoverable, :rememberable
end
# config/routes.rb
scope module: 'auth' do
devise_for :users, path: ''
devise_for :admins, path: 'admin', class_name: 'AdminUser', ...
end
# /sign_in for users, /admin/sign_in for admins
# (you can log as both at the same time)
Думает, работает хорошо, но мне нужно разрешить пользователю входить в систему с тем же адресом электронной почты на разные арендаторы / аккаунты. Во-первых, я исправил проверку:
class User < ApplicationRecord
validates :email, uniqueness: { scope: :account_id }
end
Проблема в том, что когда пользователь регистрируется / входит в систему, Devise будет искать первого пользователя с каким-либо адресом электронной почты, независимо от account_id
, поэтому, если я использовать один и тот же адрес электронной почты на поддомене 1 и поддомене2, когда я захожу на поддомен2, я получаю информацию о пользователе от поддомен1 (что неверно)
# config/initializers/devise.rb
config.request_keys = [:subdomain]
# app/models/user.rb
def self.find_for_database_authentication warden_conditions
joins(:account).where(
email: warden_conditions[:email],
accounts: {subdomain: warden_conditions[:subdomain]}
).first
end
Этот вид работает, но я обнаружил две проблемы / недостатки:
Когда я выхожу с пользователем, он делает то же самое с администратором (раздражает) для разработки)
Я хотел бы использовать account_id
на User.find_for_database_authentication
и избегать JOIN. Я не знаю, как это сделать, поскольку Devise / Warden обрабатывает subdomain
автоматически. warden_conditions
ключи должны быть email
и account_id
.