2009-09-15 10 views
2

Je cherche la meilleure façon de construire de façon propre pour construire des finder basé sur le rôle/authorisaton?Rails dynamic finders basé sur le rôle

Dans mon schéma de modèle, un user peut avoir un des rôles (défini par l'administrateur), comme administrateur, directeur régional, Sales Assistant:

Exemple Étant donné un utilisateur avec un rôle de directeur régional et a rejoint une région a, je voudrais être en mesure d'interroger ce que les autres qu'elle pouvait voir, par exemple:

regional_manager_for_region_a.users 
    => [...] # Array of users joined to region a 

regional_manager_for_region_b.users(:all, conditions => { :active => true }) 
    => [...] # Array of active users joined to region b 

administrator.users 
    => [...] # Array of all users in system 

Merci, apprécie grandement toute aide!

Répondre

2

Je pense que vous devez mettre en place un mécanisme d'autorisation.

La meilleure gemme que je connaisse est declarative_authorization. Je l'ai personnellement utilisé sur un environnement de production, et j'en suis satisfait. Il y a aussi un railscast à ce sujet. L'idée est de déclarer dans un fichier spécifique (config/authorization_rules.rb) les "rôles et permissions". Vous dites des choses comme «un gestionnaire peut lire uniquement les clients qui lui sont associés» ou «un administrateur peut lire et écrire tous les utilisateurs». Dans votre cas, il ressemblerait à ceci:

authorization do 

    role :guest do 
    # actions here can be done by everyone, even not logged in people 
    end 

    role :user do 
    includes :guest 
    # actions here can be done by logged people 
    end 

    role :manager do 
    includes :user #managers do everything users do, plus: 

    has_permission_on :sales_region, :to => :read do 
     if_attribute :id => is_in {user.sales_region_ids} 
    end 

    has_permission_on :users, :to => [:update, :read] do 
     if_attribute :id => is {user.user_ids_by_sales_region} #defined on the model 
    end 
    end 

    role :admin do 
    includes :user 
    has_permission_on [:sales_regions, :users], :to :manage 
    end 

end 

privileges do 
    privilege :manage do 
    includes :create, :read, :update, :delete 
    end 
end 

Une fois que cela est spécifié, vous devez modifier vos modèles afin qu'ils utilisent declarative_authorization. En outre, nous allons définir la méthode user_ids_by_sales_region

class User < ActiveRecord::Base 

    using_access_control # this enables DA 

    def users_by_sales_region 
    sales_regions.collect{ |sr| sr.users }.flatten.uniq 
    end 

    def user_ids_by_sales_region 
    users_by_sales_region.collect{ |u| u.id } 
    end 
end 

Vous devez également avoir une méthode current_user, et un moyen d'obtenir le rôle de l'utilisateur actuel (s). Reportez-vous à la section "Fourniture des exigences du plug-in" sur le readme.

Ensuite, vous pouvez faire ce que vous voulez avec with_permissions_to:

manager = User.find(...) 
manager.users.with_permissions_to(:read) # the users from his region 
manager.users.with_permissions_to(:read).find(:all, conditions => { :active => true }) 
manager.users.with_permissions_to(:write) #returns no users, managers can't edit them 

admin = User.find(...) 
admin.users.with_permissions_to(:write) #will return all users 

Cela signifie un peu d'effort au début, mais simplifie l'application beaucoup plus tard. En outre, vous disposez de fonctionnalités supplémentaires, telles que masquer/afficher des parties de vues en fonction des autorisations de l'utilisateur actuel, ainsi que d'interdire l'accès à des actions de contrôleur spécifiques.

En outre, il devrait fonctionner très bien avec paginations, etc.

Il y a un autre petit bijou d'autorisation déclarative appelé cancan. Je n'ai pas d'expérience avec celui-ci, mais si c'est fait par Ryan Bates, ça doit être bon (il a aussi un railscast pour ça).Cependant, je ne pense pas que cela permette des extensions de modèles, ce dont vous semblez avoir besoin maintenant.

+0

Merci pour votre réponse, ressemble certainement à un excellent plugin. J'ai finalement essayé de déclarer named_scopes sur les modèles qui nécessitaient une restriction, de sorte qu'ils pouvaient être accédés en utilisant (par exemple) User.visible_to (@current_user) ou Account.visible_to (@current_user) .in_sales_area (3). Je vais poster un exemple de code ci-dessous. Merci encore! –

0

Ma réponse ci-dessous convient aux détecteurs simples; Cependant, il n'est pas très flexible et n'est pas compatible avec le plugin will_paginate. Est-ce que quelqu'un sait d'une meilleure façon de délimiter proprement les utilisateurs @current_user est capable de gérer?

Merci


vient de répondre à ma propre question, en remplaçant l'extension de l'association par défaut comme ci-dessous. Ce serait quand même bien de savoir des commentaires ou des alternatives!

class User < ActiveRecord::Base 
    has_many :users do 
    def find(*args) 
     scope = args.first || :all 
     options = args.extract_options! 

     return User.find(args.first, options) if proxy_owner.admin? 

     users = [] 
     proxy_owner.sales_regions.collect do |sales_region| 
     users += sales_region.users 
     end 

     users.uniq 
    end 
    end 
end 
0

Juste pour donner suite à mon commentaire sur la réponse d'egarcia, j'ai finalement décidé de déclarer named_scopes sur les modèles restreints. Par exemple:

# app/models/account.rb 
class Account < ActiveRecord::Base 
    named_scope :visible_to, lambda { |user| 
    return {} if user.can_see_all_accounts? 
    { :conditions => ['sales_area_id IN (?)', user.sales_area_ids] } 
    } 
end 

# app/controllers/accounts_controller.rb 
class AccountsController < ApplicationController 
    def index 
    @accounts = Account.visible_to(@current_user) 
    ... 
    end 
end 
Questions connexes