简体   繁体   中英

Multiple Users in Devise

After 2 full days I have not been able to find a solution.

Here's my issue.

I created a rails app and added Devise. It all works great except for I have 3 devise users: Users , Vendors and Admin .

My problem is that I am trying to create separate login pages for each user. However when I generate devise views and work on the login page it only pulls the HTML from the views/devise/sessions/new page. So whether you go /admin/sign_up , /vendor/sign_up or /user/sign_up you get the exact same devise page from views/devise/sessions/new .

How can you have 3 different devise/sessions/new views ? I want the User login and sign up to look different from the Vendors and Admin logins. I have 3 devise controllers: Users_controller, Vendors_controller, and Admins_controller

I am soooo confused. Any help would be greatly appreciated.

Cheers,

You can generate three different devise models, views and controllers for Users , Admins and Vendors . You can also add devise helpers to your existing models and controllers instead. For views, make sure to use Devise's role-scoped views generator:

`rails generate devise:views users` # change `users` to whichever role you are generating

Then you can route each role to its own signup in routes.rb using their devise_for helper like so:

devise_scope :user do 
  get 'users/login'   to: 'users#sessions#new',  as 'user_login'
end

devise_scope :admin do 
  get 'admins/login',  to: 'admins#sessions#new', as 'admin_login'
end

devise_scope :vendor do
  get 'vendors/login', to: 'vendors#sessions#new', as 'vendor_login'
end

BUT:

This is not very DRY. I would strongly suggest rethinking your design and creating a single model for User with a role attribute. Try the CanCan gem . Here is CanCan's wiki on how to create role-based authorization: https://github.com/ryanb/cancan/wiki/Role-Based-Authorization

Okay, several things to look at here.


STI

First step is to get your models sorted out.

You mention you want to have Users , Vendors and Admin . I am presuming you've made several models for this, and would like to stipulate now that it will be much more beneficial for you to inherit from one model.

The single model you need to use should be User , and should extrapolate its functionality through an STI (Single Table Inheritance) :

#app/models/user.rb
class User < ActiveRecord::Base
   #columns id | type | devise | attributes | created_at | updated_at
end

#app/models/admin.rb
class Admin < User
   #No table necessary
end

#app/models/vendor.rb
class Vendor < User
   #No table necessary
end

This will allow you to use each model as if it were completely standalone, yet maintaining the flexibility of extra functionality. I can explain more about it if you need; bottom line is that you'll be FAR better off using this than separate tables.


Views

Next we have the views themselves.

The options you have for your views are as follows:

  1. Manage the selection with your routes & controllers
  2. Manage the selection in the views themselves

I would personally keep a single controller and use different views. You're using the same data, so all you need to is to either render different layouts , or different views entirely...

And, by the way, remember that Devise uses its own controllers . For your purposes, these are Sessions and Registrations respectively:

#config/routes.rb
def devise_path_names
    { sign_in: "login", sign_up: "", registration: "register", sign_out: "logout" }
end

devise_for :users,  path_names: devise_path_names #-> url.com/users/login
devise_for :admins, controllers: { sessions: "devise#sessions", registrations: "devise#registrations" }, path_names: devise_path_names #-> url.com/admins/login
devise_for :vendors, controllers: { sessions: "devise#sessions", registrations: "devise#registrations" }, path_names: devise_path_names #-> url.com/vendors/login

The above routes are untested.

It would be inadvisable to use your own controllers for the respective models - you'll have to recreate them each time, making it very WET . Instead, you'd be able to potentially do something like this:

#app/controllers/devise/sessions_controller.rb
class SessionsController < Devise::SessionsController
   before_action :set_route

   private

   def set_route
      @route = request.path.split('/')[0]
   end
end

This would pass the params you require to the devise#sessions controller.

Having said that, you could even just change the styling with the CSS classes in the views themselves:

$ rails generate devise:views users

#app/views/devise/sessions/new.html.erb
<%= form_for resource, as: resource_name, url: session_path(resource_name), class: @route do |f| %>
  ...

This will allow you to style the form as required in the CSS. It will pull the @route param through the url, allowing you to set the styling in the view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM