Domanda

Sto cercando il modo migliore per costruire un modo pulito per costruire cercatori basati su ruolo / autorizzazione?

Nel mio schema di modello, un utente può avere uno dei diversi ruoli (definiti dall'amministratore), come Amministratore, Responsabile regionale, Assistente alle vendite:

Esempio Dato un utente con un ruolo di Responsabile regionale e iscritto a una Regione A, vorrei essere in grado di interrogare ciò che altri utenti poteva vedere, ad esempio:

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

Grazie, apprezzo molto qualsiasi aiuto!

È stato utile?

Soluzione

Penso che tu debba mettere in atto un meccanismo di autorizzazione.

La gemma migliore che conosco per questo è dichiarative_authorization . L'ho usato personalmente in un ambiente di produzione e ne sono soddisfatto. C'è anche un railscast su di esso.

L'idea è che tu dichiari in un file specifico ( config / license_rules.rb ) i ruoli & autorizzazioni; " ;. Dici cose come " un manager può leggere solo i clienti ad esso associati " oppure "un amministratore può leggere e scrivere tutti gli utenti". Nel tuo caso, sembrerebbe così:

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

Una volta specificato, hai modificato i tuoi modelli in modo che utilizzino dichiarative_authorization . Inoltre, definiamo il metodo 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

Devi anche avere un metodo current_user e un modo per ottenere i ruoli dell'utente corrente. Consulta la sezione "Fornire i requisiti del plug-in" sezione sulla readme .

Quindi puoi fare quello che vuoi con 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

Ciò significa un po 'di sforzo all'inizio, ma semplifica notevolmente l'applicazione in seguito. Inoltre, hai funzionalità aggiuntive, come nascondere / mostrare parti di viste in base alle autorizzazioni dell'utente corrente, oltre a vietare l'accesso a specifiche azioni del controller.

Inoltre, dovrebbe funzionare perfettamente con impaginazioni, ecc.

C'è un'altra gemma di autorizzazione dichiarativa chiamata cancan . Non ho esperienza con questo, ma se è fatto da Ryan Bates, deve essere buono (ha un railscast anche per questo). Tuttavia, non penso che permetta l'estensione del modello, che è ciò di cui sembri aver bisogno ora.

Altri suggerimenti

La mia risposta qui sotto va bene per i cercatori semplici; tuttavia, non è molto flessibile e non è compatibile con il plug-in will_paginate . Qualcuno sa un modo migliore per definire in modo chiaro gli utenti che @current_user è in grado di gestire?

Grazie


Ho appena risposto alla mia domanda, sovrascrivendo l'estensione dell'associazione predefinita come di seguito. Sarebbe comunque bello conoscere commenti o alternative!

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

Solo per seguire il mio commento sulla risposta di egarcia, alla fine ho deciso di dichiarare named_scopes sui modelli soggetti a restrizioni. Ad esempio:

# 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top