10

Pracuję nad aplikacją Rails 3.2, w której używam Devise do uwierzytelniania. Postanowiłem wypróbować dziedziczenie pojedynczej tabeli w celu zarządzania rolami użytkowników, ale szybko wpadłem na problem. Obecnie mam trzy modele użytkowników: User < ActiveRecord, Admin < User i Collaborator < User. Administrator i Współpracownik udostępniają większość kolumn użytkowników, ale mają nieco inne zachowania i uprawnienia. Moje modele aktualnie wygląda tak:Jak radzić sobie z uwierzytelnianiem przy pomocy Devise przy użyciu wielu modeli w Rails 3.2 App

class User < ActiveRecord::Base 

    devise :database_authenticatable, :registerable, 
    :recoverable, :rememberable, :trackable, :validatable, :token_authenticatable 

    # Setup accessible (or protected) attributes for your model 
    attr_accessible :email, :name, :password, :password_confirmation, :remember_me 

    before_save :ensure_authentication_token 

    [...] 

end 

class Admin < User 
    has_one :account, dependent: :destroy 
    attr_accessible :account_attributes 
    accepts_nested_attributes_for :account 
end 


class Collaborator < User 
    has_one :account 
end 

class Account < ActiveRecord::Base 
    attr_accessible :name 
    validates_presence_of :name 
    has_many :projects, dependent: :destroy 
    has_many :users 
end 

Problem ten baran, gdy próbuję uwierzytelnić administratorów i współpracowników w moim ProjectController (i innych kontrolerów gdzie muszę uwierzytelnianie):

# Causes problem, no one can access anything. 
before_filter :authenticate_admin! 
before_filter :authenticate_collaborator! 

Podobny problem miałem był z metodami pomocniczymi devise dla np. current_user, teraz mam current_admin i current_collaborator, I „rozwiązany”, że stworzenie przed filtrem i metoda:

def set_current_user 
    @current_user = current_admin || current_collaborator 
end 

Czy istnieje podobny lub proste rozwiązanie dla mojego problemu uwierzytelniania z opracowania, lub można polecić innego podejścia niż Dziedzina pojedynczego stołu i co by to było?

Moim celem jest, 1. gdy nowi użytkownicy zarejestrują się, staną się administratorami, podczas tworzenia konta tworzony jest również model konta. 2. Nowy (Admin) użytkownik może następnie zaprosić dodatkowych użytkowników do Konta, którym będą Współpracownicy. 3. Administratorzy i Współpracownicy powinni mieć różne uprawnienia. Współpracownicy nie będą tworzyć nowych "kont" po zarejestrowaniu (firma może być lepszą nazwą dla mojego modelu konta), więc administratorzy i współpracownicy będą potrzebować nieco innych formularzy do rejestracji i edycji.

Dzięki.

Aktualizacja

Jakbym „rozwiązany” go poprzez stworzenie podobnego przed filtrem:

def authenticate! 
    if @current_user == current_admin 
    :authenticate_admin! 
    elsif @current_user == current_collaborator 
    :authenticate_collaborator! 
    end 
end 

Sugestie dotyczące ewentualnie bardziej eleganckich rozwiązań nadal będzie doceniane.

+0

szansę przetestować moją odpowiedź? – blnc

Odpowiedz

1

Możesz oddzielić całą wspólną logikę od modułu i użyć tylko tej samej tabeli.

module UserMethods 
    #... 
end 

class User < ActiveRecord::Base 
    include UserMethods 
    devise ... 

end 

class Admin < ActiveRecord::Base 
    include UserMethods 
    self.table_name = "users" 
    devise ... 
end 

i skonfigurować wszystkie modelu opracować osobno w trasach, widoki (jeśli to konieczne, patrz Configuring Views). W takim przypadku możesz łatwo przetworzyć całą logikę.

+0

Mm, dzięki. Wygląda na to, że to zadziała. Jak jednak to rozwiązanie jest lepsze niż moje obecne rozwiązanie? Przepraszam za moje nowatorskie pytanie. Oto nadchodzi kolejna. Zastanawiam się nad nieznaczną zmianą mojej logiki i zezwoleniem użytkownikom na posiadanie wielu kont, czy to administratorów, czy współpracowników dla każdego konta, relacji między użytkownikiem a kontem wielu do wielu, w jaki sposób mogę to osiągnąć za pomocą twojego lub mojego rozwiązania, i nadal mają różne role? Dzięki! – Anders

+0

Zamiast modułu, możesz wyodrębnić całą logikę do wspólnego modelu, na przykład BaseUser, umieść tutaj wszystkie relacje. Ale każda inna logika związana z tworzeniem lub atrybutami, możesz umieścić w osobnym modelu. To znaczy. wygląda na to, że twoje i moje podejście powinno być połączone. Nie lubię warunków "jeśli" w metodach, ponieważ nie jest to styl OOP. – gayavat

3

Nie wiem, czy to jest nadal potrzebne rozwiązanie do tego ...

bardziej elegancki sposób na podwójne uwierzytelnianie może być wykonanie następujących czynności:

private 

def authenticate! 
    :authenticate_admin! || :authenticate_collaborator! 
    @current_user = admin_signed_in? ? current_admin : current_collaborator 
end 

Następnie zadzwonić before_filter: uwierzytelniać !

Jeśli nie potrzebujesz uniwersalnej zmiennej "@current_user", po prostu pomiń drugą linię.

Mam nadzieję, że to pomoże.

+0

To rozwiązanie nie działa, ponieważ authenticate_admin przekieruje, jeśli nie powiedzie się ... żadnych pomysłów? Nie mogę go uruchomić – Rafal

+0

masz rację, w najnowszych wersjach to już nie działa. Zobaczę, czy uda mi się znaleźć pracę. – blnc

+0

Dodałem odpowiedź z moim rozwiązaniem – Rafal

5

Problem ten można rozwiązać stosując następujące rozwiązanie

 
def authenticate! 
    if modelA_user_signed_in? 
     @current_user = current_modelA 
     true 
    else 
     authenticate_modelB! 
    end 

    end 
Powiązane problemy