2009-09-15 57 views
2

我正在尋找構建基於角色/ authorisaton的查找器的乾淨方式的最佳方法?基於角色的Rails動態查找器

在我的模型架構,一個user可以有幾種(管理員定義)的角色,如管理員,區域經理之一,銷售助理:

給定一個帶有區域經理角色的用戶,並加入對某個區域的,我希望能夠查詢她能看到其他用戶,如:

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 

謝謝,非常感謝您的幫助!

回答

2

我想你需要設置一些授權機制。

我知道的最好的寶石是declarative_authorization。我個人在生產環境中使用過它,我對它感到滿意。關於它也有一個railscast

這個想法是你在一個特定的文件(config/authorization_rules.rb)中聲明「角色和權限」。你說諸如「經理只能讀取與之相關的客戶端」或「管理員可以讀寫所有用戶」。在你的情況下,它應該是這樣的:

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 

一旦這個規定,你必須讓他們使用declarative_authorization修改模型。此外,讓我們定義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 

你還必須有一個current_user方法,並獲取當前用戶的角色(一個或多個)的一種方式。請參閱readme上的「提供插件的要求」一節。

然後,你可以做你想要什麼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 

這意味着在開始一點點努力,但大大後來就簡化了應用。此外,您還有其他功能,例如根據當前用戶的權限隱藏/顯示部分視圖,以及禁止訪問特定的控制器操作。

而且,它應該工作只是罰款paginations等

有一個稱爲cancan另一種聲明授權寶石。我沒有這方面的經驗,但是如果是由瑞安貝茨完成的話,那一定很好(他也有這個railscast)。但是,我不認爲它允許模型擴展,這是你現在需要的。

+0

感謝您的回答,當然看起來像一個偉大的插件。 我最終試圖在需要限制的模型上聲明named_scopes,以便可以使用(例如)User.visible_to(@current_user)或Account.visible_to(@current_user).in_sales_area(3)來訪問它們。我會在下面發佈一些示例代碼。 再次感謝! – 2010-02-04 14:51:13

0

我對以下的答案很簡單的發現者;但是,它不是很靈活,並且與will_paginate插件不兼容。有誰知道更好的方式來清理範圍內的用戶@current_user是否能夠管理?

感謝


只是回答我自己的問題,通過重寫默認關聯擴展如下。儘管知道意見或備選方案仍然很棒!

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

爲了跟進我對egarcia的回答的評論,我最終決定在限制車型上宣佈named_scopes。例如:

# 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