Ruby-on-rails – Devise with multiple models & multiple login forms

authenticationdeviseruby-on-railsruby-on-rails-3

I'm using rails 3.2 and devise 2.1 to create a multi-site CMS

Requirements

  • Sites based Basecamp subdomains.
  • Have 3 "user" models. 1. Admin(superuser) 2. Authors(each have their own site on subdomain) & Subscribers(read the sites ).
  • Authors: registration is normal username/password combo but needs to be approved by admin. their registration form will have subdomain field.
  • Subscribers: registration happens by invitation email.
  • need separate login & registration forms

Possible Solutions

I have been searching & found few solutions

  • 3 Separate models in devise:
$ rails generate devise admin 
$ rails generate devise author
$ rails generate devise subscriber

but this gives the following error

$ rails generate devise author
/home/gaurish/.rvm/gems/ruby-1.9.3-p286-perf/gems/devise-2.1.2/lib/devise/rails/routes.rb:443:in 'raise_no_devise_method_error!': Admin does not respond to 'devise' method. This usually means you haven't loaded your ORM file or it's being loaded too late. To fix it, be sure to require 'devise/orm/YOUR_ORM' inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb' (RuntimeError)

  • STI: single table in the database and for each user type create a model
     class Admin < User; end
     class Author < User; end
     class Subscriber < User; end

Here, I am not sure how this would handle different login/registration workflows. example for subscriber I am planning on using devise_invitable for creating invitations. Admin doesn't need to scoped on basis of subdomains unlike authors & subscribers.

Does this seem complicated? I hope I was able to explain well.

Best Answer

You don't need to have three separate models to build this functionality. What you want to look at is the concept of Roles which are applied to one User model.

There is a Gem which provides this capability called Rolify and can be found at https://github.com/EppO/rolify

This would allow you to specify which users are in which Roles and change them as you see fit, all from one existing model.

Once you have Roles attached to the User model, you can override Devise's registration controllers to detect the Role and render different templates etc. You would do this by:

  1. Running rails generate devise:views to unpack the views from the Devise gem into your project
  2. Create your own Registrations controller:

    # app/controllers/registrations_controller.rb
    class RegistrationsController < Devise::RegistrationsController
      def new
        super
        # Add logic here to detect Role and display different forms
      end
    
      def create
        super
      end
    
      def update
        super
      end
    end 
    
  3. Add the correct settings in your routes.rb file to tell Devise to use your new controller:

    # app/config/routes.rb
    devise_for :users, :controllers => {:registrations => "registrations"}