Pregunta

¿Estoy buscando la mejor manera de construir una forma limpia de construir buscadores basados ??en roles / autorizaciones?

En el esquema de mi modelo, un usuario puede tener uno de varios roles (definidos por el administrador), como Administrador, Gerente regional, Asistente de ventas:

Ejemplo Dado un Usuario con un rol de Gerente Regional y unido a una Región A, me gustaría poder consultar qué otros usuarios podría ver, por ejemplo:

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

¡Gracias, agradezco mucho cualquier ayuda!

¿Fue útil?

Solución

Creo que necesita establecer algún mecanismo de autorización.

La mejor gema que conozco para esto es declarative_authorization . Lo he usado personalmente en un entorno de producción, y estoy satisfecho con él. También hay un railscast al respecto.

La idea es que declare en un archivo específico ( config /autorization_rules.rb ) los "roles y permisos". Dices cosas como "un gerente puede leer solo los clientes asociados con él". o "un administrador puede leer y escribir a todos los usuarios". En su caso, se vería así:

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 vez que se especifica esto, debe modificar sus modelos para que utilicen declarative_authorization . Además, definamos el método 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

También debe tener un método current_user y una forma de obtener los roles del usuario actual. Consulte los "Requisitos del complemento" # 8217; s sección sobre readme .

Entonces puede hacer lo que quiera 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

Esto significa un poco de esfuerzo al principio, pero simplifica mucho la aplicación más adelante. Además, tiene funcionalidades adicionales, como ocultar / mostrar partes de vistas según los permisos que tenga el usuario actual, así como prohibir el acceso a acciones específicas del controlador.

Además, debería funcionar bien con paginaciones, etc.

Hay otra gema de autorización declarativa llamada cancan . No tengo experiencia con este, pero si Ryan Bates lo hace, debe ser bueno (tiene un railscast para ello también). Sin embargo, no creo que permita extensiones de modelo, que es lo que parece necesitar ahora.

Otros consejos

Mi respuesta a continuación está bien para buscadores simples; sin embargo, no es muy flexible y no es compatible con el complemento will_paginate . ¿Alguien sabe de una mejor manera de determinar de manera limpia los usuarios que @current_user puede administrar?

Gracias


Acabo de responder mi propia pregunta, anulando la extensión de asociación predeterminada como se muestra a continuación. ¡Sin embargo, sería genial saber comentarios o alternativas!

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 para seguir mi comentario sobre la respuesta de egarcia, finalmente decidí declarar named_scopes en los modelos restringidos. Por ejemplo:

# 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top