Welcome to End Point’s blog

Ongoing observations by End Point people

Spree Authorization Failure for Customized Role

Hello again all. Recently I was working on another Spree site running Spree 2.1.1. The client wanted to create some custom roles. For example, the client wanted there to be a Sales Manager role. A Sales Manager could log in and have read and write access to all the orders. However, a sales manager should not have read/write access to products, configuration, promotions, users, etc. This was easily accomplished by following the steps in the Spree documentation. As I will describe, this documentation assumes that the custom role will have access to Orders#index.

The client wanted to create a second custom role that had create, read, update and delete access to the Training model and nothing more. The training model belongs to a taxon and has a unique event date and taxon id. An example would be a training instance with an event date of September 9th, 2014 that belongs to a taxon with the name "Fire Safety 101" and a description "Teaching fire safety in accordance with OSHA standards. 10 hours and lunch is provided". So, I planned to create a training personnel role that should be able to log in and only have read/write access to Trainings. However, the Spree documentation did not provide an explanation on how to create a custom role that does not have read or write access to orders.


Following the pattern described in the Spree documentation for creating custom roles and their respective authorization, I created an ability_decorator.rb with the contents:

class AbilityDecorator
     include CanCan::Ability
     def initialize(user)
       if user.respond_to?(:has_spree_role?) && user.has_spree_role?('sales_manager')
         can [:admin, :index, :show], Spree::Order
       if user.respond_to?(:has_spree_role?) && user.has_spree_role?('training')
         can [:admin, :manage], Spree::Training

However, after creating a training user and attempting to log in, I got an unauthorized error. So, I checked the logs:

The log output above shows that while I was logged in as a user with the training role, the application was checking for authorization on Spree::Admin::OrdersController#index (the orders list page), because the base admin URL ("/admin") points to this controller action. I reviewed the Devise documentation to modify where a user with the training role is redirected to upon login (via Spree Auth Devise's after_sign_in method), as shown in the code shown below.

def after_sign_in_path_for(resource)
    stored_location_for(resource) ||
      if resource.is_a?(Spree::User) && resource.has_spree_role?('training')

After making this change, I tried once again and was able to successfully log in as a training user and only have the desired access to Trainings.


To summarize, if you'd like to have a custom role and not give them access to Orders, you will need to make some adjustments outside the steps listed in Spree's documentation for custom role authorization.

No comments: