Rails dynamic search engines based on role

I am looking for the best way to build a clean way to build role / author based crawlers?

In my model, the model user

can have one of several (administrator-defined) roles such as Administrator, Regional Manager, Sales Assistant:

An example . Given a user with the role of Regional Manager and joined to Region A, I would like to be able to query what other users she might see, for example:

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

      

Thanks, really appreciate any help!

+2


source to share


3 answers


I think you need to create an authorization mechanism.

The best gem I know for this is declarative_authorization . I've personally used it in a production environment and I'm happy with it. There's a railscast about this too.

The idea is that you declare config/authorization_rules.rb

"roles and permissions" in one specific file ( ). You say things like "the manager can only read the clients associated with him" or "the administrator can read and write all users". In your case it will look like this:

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

      

Once this is indicated, you will change your models to use declarative_authorization

. Also, define a methoduser_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

      



You should also have a method current_user

and a way to get the current user role. See the Providing Requirements for Plugins section on the readme .

Then you can do what you want with 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

      

This means that it takes a little effort in the beginning, but will greatly simplify the application later. In addition, you have additional functionality such as hiding / showing parts of the views depending on the permissions of the current user, as well as denying access to certain controller actions.

Also, it should work just fine with pagination etc.

There's another declarative authorization graph called cancan . I have no experience with this, but if done by Ryan Bates it should be fine (he got a railscast for him too). However, I don't think it allows the model extension that you need right now.

+2


source


My answer below is suitable for simple searchers; however, it is not very flexible and not plugin compatible will_paginate

. Does anyone know how to best use the users @current_user

who can manage?

thank




Just answered my own question by overriding the default association extension as shown below. It would be great to know the comments or alternatives though!

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


source


To follow up on my comment on egarcia's answer, I ended up settling on an ad named_scopes

on limited models. For example:

# 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

      

0


source







All Articles