-
Notifications
You must be signed in to change notification settings - Fork 5.5k
How to: Scope login to subdomain
- Modify the Devise-generated migration to remove the index on email uniqueness constraint
- Change login keys to include
:subdomain - Override Devise hook method
find_for_authentication
First, you must remove the email index uniqueness constraint. Because we'll be turning this into a scoped query, we will scope the new index to subdomain. If this is a brand new Devise model, you can open the Devise migration and change the following:
# db/migrate/XXX_devise_create_users.rb
def change
# Remove this line
add_index :users, :email, :unique => true
# Replace with
add_index :users, [:email, :subdomain], :unique => true
endIf this is an existing project, you'll need to create a new migration removing the old index and adding a new one:
rails g migration reindex_users_by_email_and_subdomain# db/migrate/XXX_reindex_users_by_email_and_subdomain.rb
def change
remove_index :users, :email
add_index :users, [:email, :subdomain], :unique => true
endIn your Devise model, add :subdomain to :request_keys. By default :request_keys is set to [].
# app/models/user.rb
class User
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, request_keys: [:subdomain]
endIf you have multiple Devise models and you would like all of them to have the same :request_keys configuration, you can set that globally in config/initializers/devise.rb
config.request_keys = [:subdomain] # default value = []If additionally you want to still be able to log in using a URL without a subdomain, :request_keys can also take a hash with booleans indicating if the key is required or not.
config.request_keys = { subdomain: false }If you do, :validatable will prevent more than one record having the same email, even in different subdomains. If you want to keep some of the validations, you can copy the ones you want from https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb
For Authenticatable, Devise uses the hook method Model.find_for_authentication. Override it to include your additional query parameters:
# app/models/user.rb
class User < ActiveRecord::Base
def self.find_for_authentication(warden_conditions)
where(:email => warden_conditions[:email], :subdomain => warden_conditions[:subdomain]).first
end
endCongrats, User login is now scoped to subdomain!