역할에 따른 Rails 동적 파인더
-
07-07-2019 - |
문제
역할/권한 기반 찾기를 구축하는 깔끔한 방법을 구축하는 가장 좋은 방법을 찾고 있습니까?
내 모델 스키마에서는 user
관리자, 지역 관리자, 영업 보조원과 같은 여러 (관리자가 정의한) 역할 중 하나를 가질 수 있습니다.
예 지역 관리자 역할을 갖고 지역 A에 가입한 사용자가 있는 경우, 그녀가 볼 수 있는 다른 사용자가 무엇인지 쿼리할 수 있기를 원합니다. 예:
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
감사합니다. 도움을 주시면 대단히 감사하겠습니다!
해결책
내 생각에는 인증 메커니즘을 마련해야 할 것 같습니다.
내가 아는 최고의 보석은 다음과 같습니다. 선언적 승인.개인적으로 프로덕션 환경에서 사용해본 결과 만족스럽습니다.거기에 레일캐스트 그것에 대해서도요.
아이디어는 하나의 특정 파일(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
방법 및 현재 사용자의 역할을 가져오는 방법이 있습니다."플러그인 요구 사항 제공" 섹션을 참조하세요. 읽어보기.
그러면 당신은 당신이 원하는 것을 할 수 있습니다 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
이는 처음에는 약간의 노력이 필요하지만 나중에는 응용 프로그램이 크게 단순화된다는 의미입니다.또한 현재 사용자의 권한에 따라 뷰의 일부를 숨기거나 표시하고 특정 컨트롤러 작업에 대한 액세스를 금지하는 등의 추가 기능도 있습니다.
또한 페이지 매김 등에서도 잘 작동합니다.
이라는 또 다른 선언적 인증 gem이 있습니다. 캉캉.나는 이것에 대한 경험이 없지만 Ryan Bates가 이 작업을 수행했다면 분명 좋을 것입니다. 레일캐스트 그것을 위해서도 마찬가지입니다).그러나 나는 그것이 지금 필요한 것처럼 보이는 모델 확장을 허용한다고 생각하지 않습니다.
다른 팁
아래 내 대답은 간단한 찾기에 적합합니다.그러나 유연성이 부족하고 다음과 호환되지 않습니다. 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
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