Search code examples
ruby-on-railsrubyruby-on-rails-3devisescopes

What's the best way to handle logging in and out with multiples scopes/roles with Rails/Devise?


I've been searching through the Devise RDocs, Google, on this site for answers to my question, but no luck.

Let's say I have four Devise scopes/roles, and each one has their own attributes, login page, and separate web flows:

  • Students
  • Professors
  • Deans
  • Faculties

All of these use the User class and have the following attribues in common.

  • Id
  • Name
  • Email
  • Password
  • Role

Here is an example of the routes I have established to set this up:

devise_for :students, :class_name => 'User'
devise_for :professors, :class_name => 'User'
devise_for :deans, :class_name => 'User'
devise_for :faculties, :class_name => 'User'
devise_for :users

Then I generated the devise scoped views and played around with those.

After that I had to add some code in my application controller to override Devise::RegistrationsController which wanted to route everything to the root path:

def after_sign_in_path_for(resource)
 user_role = resource.role
 case user_role
   when "professor"
     professors_url
   when "faculty"
     faculties_url
   when "dean" 
     deans_url
   when "student"
     students_url
   else
     root_path       
  end 
end

def after_sign_out_path_for(resource)
  case resource
   when :faculty
     new_faculty_session_path
   when :professor
    new_professor_session_path
   when :dean 
     new_dean_session_path
   when :student
     new_student_session_path
   else
     root_path       
  end     
end

I have access to excellent helpers such as signed_in? which tells me if any user in any one of the scopes mentioned above is logged in. Great!!! Now I need similar functionality for current_user.

I have access to the following helpers.

  • current_student
  • current_professor
  • current_dean
  • current_faculty

They work perfectly, but here is where I have issues. Let's say if I have a view that shares all of these scopes. Now if I try current_student on that view and I'm logged in as a professor it won't work.

For example: I have a partial that I want to include on every page to allow users to logout if they're logged in. This is how I went about it for a student. Works just fine.

<% if student_signed_in? %>
 <div style="float: right;">Welcome <%= current_student.name %></div>
 <div>
    <%= link_to('Logout', destroy_student_session_path, :method => :delete) %>        
 </div>
<% end %>

What I want to do is something like this which will provide the ability to logout all my scopes/resources regardless if I'm logged in as a student, dean, professor, or faculty:

<% if signed_in? %>
 <div style="float: right;">Welcome <%= current_resource.name %></div>
 <div>
    <%= link_to('Logout', destroy_resource_session_path, :method => :delete) %>        
 </div>
<% end %>

My next step would have been to add my own helper methods to determine the scope like so:

def current_resource
     current_professor unless current_professor.nil?
     current_student unless current_student.nil?
     current_dean unless current_dean.nil?
     current_faculty unless current_faculty.nil?
end

def destroy_resource_session_path
     destroy_professor_session_path unless current_professor.nil?
     destroy_student_session_path unless current_student.nil?
     destroy_dean_session_path unless current_dean.nil?
     destroy_faculty unless current_faculty.nil?
end

If this approach will work, I'd do it, but it seems highly inefficient and tedious if I decide to add more roles or common functionality in the future...

There has to be a better way? This makes me feel like I'm using Devise incorrectly, or am just missing something somewhere.


Solution

  • After much more research I found a Gem called CanTango that does exactly what I was looking for. It works with Devise and handles multiples User model types. Take a look and see.

    https://github.com/kristianmandrup/cantango/wiki/Cantango-with-devise-accounts

    Thanks for answering my questions guys. I learned a lot from your answers.