Skip to content

Instantly share code, notes, and snippets.

@tiagobbraga
Created September 28, 2016 20:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiagobbraga/21b4c79841022072732c6cba6583f5de to your computer and use it in GitHub Desktop.
Save tiagobbraga/21b4c79841022072732c6cba6583f5de to your computer and use it in GitHub Desktop.
Unified sign in form for multiple types of Devise users.
# Monkey patch to remove memoization from Devise mapping lookup.
# We need to be able to switch between different mappings at runtime
# in order to authenticate different types of users.
module Devise
module Strategies
class Base
def mapping
# @mapping ||= begin
mapping = Devise.mappings[scope]
raise "Could not find mapping for #{scope}" unless mapping
mapping
# end
end
end
end
end

An application I'm working on has two different types of Devise users, but I want both types of users to be able to use the same sign in form. Devise doesn't make this easy.

You could argue that I really should have a single user type with a role attribute, but the app is far enough along that I don't want to change that early design decision. It could be changed later if more pain points are discovered.

You could also argue that I shouldn't use Devise, but it's still the de facto authentication standard for Rails applications.

In this example, you can sign in as either a User or an AdminUser. This application only has two types of user, but this example could be extended to support any number of them more gracefully.

MyApp::Application.routes.draw do
devise_for :users, controllers: { sessions: 'sessions' }
devise_for :admin_users, controllers: { sessions: 'sessions' }
end
class SessionsController < Devise::SessionsController
def create
# try to authenticate as a User
self.resource = warden.authenticate(auth_options)
resource_name = self.resource_name
if resource.nil?
# try to authenticate as an AdminUser
resource_name = :admin_user
request.params[:admin_user] = params[:user]
self.resource = warden.authenticate!(auth_options.merge(scope: :admin_user))
end
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment