Rails, Devise: same resource, different controller based on user type

I have a resource, say Product , which can be accessed by two different user classes: say Customer and Admin . Inheritance between the two does not exist.

I use Devise for authentication:

 # config/routes.rb devises_for :customers deviser_for :admins 

I have these two controllers:

 # app/controllers/customers/products_controller.rb class Customers::ProductsController < ApplicationController 

and

 # app/controllers/admins/products_controller.rb class Admins::ProductsController < ApplicationController 

Now, depending on who is logging in ( Customer or Admin ), I want products_path point to the appropriate controller. And I want to avoid customers_products_path and admins_products_path , which is messy.

So, I set up my routes as such

 # config/routes.rb devise_scope :admin do resources :products, module: 'admins' end devise_scope :customer do resources :products, module: 'customers' end 

This does not work. When I log in as Customer , products_path still points to Admins::ProductsController#index , as it is defined first.

Any clue? What I want to do may just be impossible without hacking.

UPDATE According to the code , this is not feasible.

+1
ruby-on-rails devise routes
source share
2 answers

Turns out the best way to achieve this is to use routing restrictions as such:

 # config/routes.rb resources :products, module: 'customers', constraints: CustomersConstraint.new resources :products, module: 'admins', constraints: AdminsConstraint.new # app/helpers/customers_constraint.rb class CustomersConstraint def matches? request !!request.env["warden"].user(:customer) end end # app/helpers/admins_constraint.rb class AdminsConstraint def matches? request !!request.env["warden"].user(:admin) end end 

I saved the restriction objects in a subfolder because I really don't know the best place to put them.

Thanks to @crackofdusk for the tip.

+2
source share

To do this, you will need to replace the existing after_sign_in_path_for with the testament method. Put this in your app/controllers/application_controller.rb

 def after_sign_in_path_for(resource) if resource.class == Admin '/your/path/for/admins' elsif resource.class == Customer '/your/path/for/customers' end end 

Note : If you want to implement the previous_url requested by the user, then you can use it as follows:

  session[:previous_url] || 'your/path/for/admins' 
+1
source share

All Articles