问题
I have a resource, say Product
, which can be accessed by two different user classes: say Customer
and Admin
. There is no inheritance between these two.
I am using 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 logs in (Customer
or Admin
), I want products_path
to point to the corresponding controller. And I want to avoid having customers_products_path
and admins_products_path
, that's messy.
So I have setup 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 doesn't work. When I login as a Customer
, products_path
still points to Admins::ProductsController#index
as it is the first defined.
Any clue? What I want to do might simply be impossible without hacking.
UPDATE According to the code, it is not doable.
回答1:
It turns out the best way to achieve that is to use routing constraints 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 stored the constraint objects in the helper folder because I don't really know the best place to put them.
Thanks to @crackofdusk for the tip.
回答2:
For this you will need to override the existing after_sign_in_path_for method of devise. 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 previous_url
that was requested by user then you can use it like this:
session[:previous_url] || 'your/path/for/admins'
来源:https://stackoverflow.com/questions/20492370/rails-devise-same-resource-different-controller-based-on-user-type