2009-10-15 10 views
3

J'ai une grande application Rails qui a 34 types d'utilisateurs différents grâce à l'héritage de table unique. Lorsque l'application a été initialement conçue, il a été supposé que l'utilisateur aurait des comportements différents en fonction du type. Cette hypothèse était fausse, alors je cherche à refactoriser.Meilleure façon de gérer différents types d'utilisateurs?

La question est de savoir comment vous refactoriser l'utilisateur STI?

  • Ajouter une tonne d'attributs booléens à l'utilisateur (par exemple. User#is_employee?, User.is_contractor?)
  • Renommer User#type-User#user_type et qu'aligner string faire en fonction du champ
  • une solution table de recherche horribles
  • Quelque chose que je 'm manquant ...

Juste pour clarifier, un utilisateur a besoin d'un' type 'pour des raisons ACL, mais avec STI ils sont vraiment juste des modèles vides sd STI provoque des problèmes de spécification, des douleurs générales dans le cul, etc.

Répondre

0

Les 34 modèles sont-ils vides?

S'ils vous pouvez faire:

self.inheritance_column = nil 

En haut de votre modèle d'utilisateur, de cette façon vous pouvez simplement vérifier le type:

if @user.type == "Employee" 
    # do something 
end 
+0

Intéressant et simple ... –

0

Il est difficile de répondre à la question sans savoir De quelle façon vos 'raisons ACL' utiliseront le type, mais ...

Dans mon expérience, je suis toujours allé avec User#user_type. Il s'est toujours avéré pour moi que les cas étaient assez rares pour que cela soit bon. Bien que j'ai seulement eu quelques types d'utilisateurs. Une autre option (qui pourrait être ce que vous faites allusion à votre deuxième option) serait d'utiliser method_missing pour gérer la correspondance de chaîne, et lui permettre de se comporter comme l'option 1.

Par exemple:

def method_missing(method, *args, &block) 
if(method.to_s.starts_with?('is_')) 
    self.user_type == method.to_s.gsub("is_", "").gsub("?", "") 
end 
end 

cela retournerait vrai pour is_contractor? si le user_type est entrepreneur.

Notez que l'extrait fourni n'a pas été testé et que les gsub chaînés sont assez affreux. Je suis sûr que cela peut être écrit comme une belle petite expression régulière ou d'une autre manière intelligente.

3

Il semble que ce dont vous avez vraiment besoin, ce sont les rôles plutôt que les types d'utilisateurs. J'ai constaté que c'est généralement le cas lorsque vous vous retrouvez avec de nombreux types d'utilisateurs, parce que certains utilisateurs ont plus d'un rôle. Un modèle ACL simple est: L'utilisateur a de nombreux rôles, chaque rôle a de nombreuses autorisations. Le jeu d'autorisations pour un utilisateur est l'ensemble des autorisations pour tous les rôles auxquels l'utilisateur appartient.

Dans les cas plus complexes, une autorisation est souvent une propriété calculée plutôt qu'une ligne dans une base de données, pour la simple raison que les autorisations sont parfois basées sur la cible et le temps (!).

@user.can_view_payroll_info_for?(@employee, 2.years.ago) ==> true 
@user.can_view_payroll_info_for?(@employee, Time.now) ==> false 

La plupart du temps cependant, un rôle est aussi haute résolution que vous devez obtenir:

@john.has_role(:content_author) ==> true 
@john.has_role(:moderator) ==> true 

@benny.has_role(:content_author) ==> true 
@benny.has_role(:moderator) ==> false 

@michael.has_role(:moderator) ==> true 
@michael.has_role(:content_author) ==> false 

Vous pouvez la mettre en œuvre aussi simplement que séparées par une virgule (validée) chaîne colonne « rôles » pour l'utilisateur ou une table de jointure si vous souhaitez que les rôles soient normalisés.

Questions connexes