2011-01-20 5 views
22

Pracuję nad aplikacją do zarządzania projektami, a w aplikacji mam project_managers i klientów. Używam Devise i CanCan do uwierzytelniania/autoryzacji.Jak mogę przekierować ścieżkę główną użytkownika (root) użytkownika na podstawie jego roli za pomocą narzędzia Devise?

W którym momencie po zalogowaniu powinienem przekierować użytkownika do jego własnego kontrolera/układu/widoków? Czy istnieje sposób sprawdzenia, czy current_user.role wi ustawić root (lub przekierowanie) na podstawie tego, czy są one menedżerem projektu lub klienta? Czy to jest zmiana, którą mogę wprowadzić gdzieś w Devise?

Dzięki z góry za wszelką pomoc! - Mark

+0

Zadałem podobne pytanie: http://stackoverflow.com/questions/3799393/rails-routes-root-with-nested-resource - odpowiedź polegała na stworzeniu oddzielnego kontrolera dla strony głównej, która wykonuje routing. Nie możesz uzyskać dostępu do tych informacji w narzędziu Devise w routes.rb. – Skilldrick

Odpowiedz

32

Twój plik routes.rb nie będzie miał pojęcia, jaką rolę ma użytkownik, więc nie będzie można go użyć do przypisania określonych tras głównych.

Co możesz zrobić, to skonfigurować kontroler (na przykład passthrough_controller.rb), który z kolei może odczytać rolę i przekierowanie. Coś takiego:

# 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' 

ten sposób wszyscy użytkownicy będą mieć jeden punkt wejścia, co z kolei przekierowuje je do odpowiedniego kontrolera/akcji w zależności od ich roli.

+0

Dzięki człowieku, to się udało. – Mark

+2

http://stackoverflow.com/questions/4753871/how-can-i-redirect-a-users-home-root-path-based-on-their-rola-using-devise/4754097#4754097 jest lepszą implementacją , ponieważ nie tworzy nowego kontrolera tylko w celu przekierowania. Ponadto spowodowałoby to 1 dodatkową podróż w obie strony z przeglądarki na serwer za każdym razem, gdy użytkownik zostanie przekierowany na ścieżkę root_path –

+0

Eleganckie rozwiązanie, które nie wymaga zmiany żadnego istniejącego kodu, tzn. Mogę zachować wszystkie instrukcje "redirect_to root_path" tak, jak były wcześniej. Podoba mi się :) – Wolfgang

6

Robię to w aplikacji Rails 3, która używa Strażnika. Ponieważ Devise jest zbudowany na Warden, myślę, że zadziała on dla ciebie, ale pamiętaj, aby poeksperymentować z nim trochę, zanim polegniesz na nim.

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' 

Jeśli rola użytkownika jest „project_manager” THE ProjectManagersController zostaną wykorzystane - jeśli to nie zostanie użyty ClientsController. Jeśli w ogóle się nie zalogują, env['warden'].user będzie nieważne, a otrzymasz komunikat o błędzie, więc prawdopodobnie będziesz chciał to obejść, ale to pomoże Ci zacząć.

+0

Dzięki za odpowiedź! Próbowałem tego najpierw, ale nie mogłem go uruchomić (prawdopodobnie dlatego, że jestem nowy). Nie wspominając o tym - ledwo mogę zrozumieć, co robię w tym momencie, więc pomysł "eksperymentowania z tym" jest straszny jak diabli! – Mark

13

Najprostszym rozwiązaniem jest użycie lambda:

root :to => 'project_managers#index', :constraints => lambda { |request| request.env['warden'].user.role == 'project_manager' } 
root :to => 'clients#index' 
+0

To zadziałało dla mnie. Mam jednak pytanie. Używam Ruby 2.3.0 i pozwala mi to używać nowej pałecznej składni lambda. Ale dostaję błąd składniowy z 'constraints: -> {...}'. Działa to dobrze, jeśli używam 'lambda' zamiast' -> '. Masz pomysł? – artificis

10

Inną opcją jest zdać proc metody authenticated tak (używam rolify w ten przykład):

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" 

Należy zauważyć, że w Rails 4 masz do określon y unikalna nazwa dla każdej trasy głównej, patrz: this issue w celu uzyskania szczegółowych informacji.

+1

to rozwiązanie jest bardzo czyste dzięki zaktualizowanej składni –