Как с помощью Devise перенаправить домашний (корневой) путь пользователя в зависимости от его роли?

Я работаю над приложением для управления проектами, и в приложении у меня есть project_managers и клиенты. Я использую Devise и CanCan для аутентификации/авторизации.

В какой момент после входа в систему я должен перенаправлять пользователя на свой собственный контроллер/макет/представления? Есть ли способ проверить current_user.role в routes.rb и установить корень (или перенаправление) в зависимости от того, является ли он менеджером проекта или клиентом? Это изменение я могу внести где-нибудь в Devise?

Заранее благодарю за любую помощь! --Отметка


person Mark    schedule 20.01.2011    source источник
comment
Я задал аналогичный вопрос: stackoverflow.com/ вопросов/3799393/ - ответ был в том, чтобы создать отдельный контроллер для домашней страницы, который выполняет маршрутизацию. Вы не можете получить доступ к этой информации Devise внутри route.rb.   -  person Skilldrick    schedule 21.01.2011


Ответы (5)


Ваш файл routes.rb не будет знать, какая роль у пользователя, поэтому вы не сможете использовать его для назначения конкретных корневых маршрутов.

Что вы можете сделать, так это настроить контроллер (например, passthrough_controller.rb), который, в свою очередь, может читать роль и перенаправлять. Что-то вроде этого:

# passthrough_controller.rb
class PassthroughController < ApplicationController
  def index
    path = case current_user.role
      when 'project_manager'
        some_path
      when 'client'
        some_other_path
      else
        # If you want to raise an exception or have a default root for users without roles
    end

    redirect_to path     
  end
end

# routes.rb
root :to => 'passthrough#index'

Таким образом, у всех пользователей будет одна точка входа, которая, в свою очередь, перенаправляет их к соответствующему контроллеру/действию в зависимости от их роли.

person vonconrad    schedule 20.01.2011
comment
stackoverflow.com/questions/4753871/ - лучшая реализация, поскольку она не создает новый контроллер только для перенаправления. Кроме того, это приведет к 1 дополнительной передаче данных из браузера на сервер каждый раз, когда пользователь перенаправляется на root_path. - person Khaja Minhajuddin; 24.10.2011
comment
Элегантное решение, не требующее изменения какого-либо существующего кода, т.е. я могу оставить все операторы redirect_to root_path такими, какими они были раньше. Мне это нравится :) - person Wolfgang; 08.03.2012
comment
Это хорошо работает для меня. Я решил бросить его в свой контроллер приложений, и все кажется денди... Но есть ли причина, по которой вы настроили для него совершенно новый контроллер? Просто интересно, не упускаю ли я что-то. - person counterbeing; 19.02.2013

Самое простое решение — использовать lambda:

root :to => 'project_managers#index', :constraints => lambda { |request| request.env['warden'].user.role == 'project_manager' }
root :to => 'clients#index'
person collimarco    schedule 03.08.2012
comment
Это сработало для меня. У меня есть вопрос. Я использую Ruby 2.3.0, и это позволяет мне использовать новый синтаксис stabby lambda. Но я получаю синтаксическую ошибку с constraints: -> { ... }. Он отлично работает, если я использую lambda вместо ->. Любая идея об этом? - person elquimista; 06.04.2016
comment
Предполагается, что можно использовать proc/lambda для опции :to (root to: proc { |env| ...}), но я столкнулся с различными проблемами, так как это, кажется, ломает url_for. Это решение работало без нарушения url_for. +1! - person Steve; 13.03.2019

Другой вариант — передать процедуру методу authenticated следующим образом (в этом примере я использую rolify):

authenticated :user, ->(u) { u.has_role?(:manager) } do
  root to: "managers#index", as: :manager_root
end

authenticated :user, ->(u) { u.has_role?(:employee) } do
  root to: "employees#index", as: :employee_root
end

root to: "landing_page#index"

Обратите внимание, что в Rails 4 вы должны указать уникальное имя для каждого корневого маршрута, см. эту проблему для подробностей.

person HargrimmTheBleak    schedule 02.02.2014
comment
давайте проголосуем за этот ответ! следует принять за правильное - person mmike; 12.12.2018
comment
Есть ли способ использовать пользователя при выборе пути? т.е. root to: organization_path(user.organization) - person thisismydesign; 17.02.2021

Я делаю это в приложении Rails 3, которое использует Warden. Поскольку Devise построен на основе Warden, я думаю, он вам подойдет, но не забудьте немного поэкспериментировать с ним, прежде чем полагаться на него.

class ProjectManagerChecker
  def self.matches?(request)
    request.env['warden'].user.role == 'project_manager'
  end
end

# routes.rb
get  '/' => 'project_managers#index', :constraints => ProjectManagerChecker
get  '/' => 'clients#index'

Если роль пользователя — «project_manager», будет использоваться ProjectManagersController, если нет — ClientsController. Если они вообще не вошли в систему, env['warden'].user будет равно нулю, и вы получите сообщение об ошибке, поэтому вы, вероятно, захотите обойти это, но это поможет вам начать.

person PreciousBodilyFluids    schedule 21.01.2011
comment
Спасибо за ответ! На самом деле я сначала попробовал это, но не смог заставить его работать (вероятно, потому что я новичок в этом). Не говоря уже о том, что я едва могу понять, что я делаю в этот момент, поэтому идея экспериментировать с этим чертовски страшна! - person Mark; 21.01.2011

Сообщение в блоге с реализацией http://minhajuddin.com/2011/10/24/how-to-change-the-rails-root-url-based-on-the-user-or-role/

person Khaja Minhajuddin    schedule 24.10.2011