← Back to Upcase

Performance in serialized-array based permissions


(João Daniel) #1

I’m not sure about how to deal with this permission hierarchy. The application have many users and many customers. Some users are C-level and have access to all customers, some are regional sales managers, some are account managers and others are salespeople. This “structure” is not fixed, but each user should just have access to the customers he/she is related to.

I’m thinking of using a serialized array to store the customers id each user have access to. The question is: since it needs to deserialize the array in ruby, it certainly have some performance issues. Is this an acceptable approach, considering that almost every request of the application will require this permission validation?


(Joel Quenneville) #2

The problem with this approach is that you are introducing data redundancy. If a new customer gets added to the system, you have to go and update all the users that have access to that customer. Same when deleting a customer. When you promote a user, you need to recalculate all the customers they have access to.

The standard approach is to calculate the customers that can be accessed by a user at run time. This could be as simple as checking that a customer is associated to a user:

allowed_customers = current_user.customers

For a more complex permissions scheme it is useful to encapsulate that logic in policy objects such as those provided by pundit.

class CustomerPolicy
  class Scope
    def initialize(user, customers)
      @user = user
      @customers = customers
    end

    def resolve
      if @user.c_level?
        @customers
      elsif @user.regional_sales_manager?
        @customers.where(region: @user.region)
      else
        @customers.none
      end
    end
  end
end

Then you can say:

allowed_customers = CustomerPolicy::Scope.new(current_user, Customer.all).resolve

or if using the pundit helpers:

allowed_customers = policy_scope(Customer.all)