APIDeveloperUserReleasesDemoContact
  • Core

    • Stores
    • Orders
    • Products
    • Payments
    • Shipments
    • Inventory
    • Promotions
    • Adjustments
    • Taxation
    • Calculators
    • Addresses
    • Preferences
  • Customization

    • Storefront
    • Templates
    • Assets (JS & CSS)
    • Images
    • Dependency system
    • Business Logic
    • Checkout Flow
    • Permissions
    • API v2
    • API v1
    • Authentication
    • Internationalization
    • Extensions
    • Emails
  • Security

    • Security
    • PCI Compliance
    • Authentication and Authorization
    • API
  • Source

    • About the Code
    • Getting Help
    • Navigating the Source
  • Tutorials

    • Getting Started with Spree
    • Add Spree to an existing Ruby on Rails application
    • Developing Spree
    • Improve SEO
    • Creating an Extension
    • Deface Overrides
    • Extend Product Attributes
    • Testing Spree Applications
    • Updating Extensions to Rails 6 and Spree 4
  • Upgrades

    • Upgrading Spree 4.1 to 4.2
    • Upgrading Spree 4.0 to 4.1
    • Upgrading Spree 3.7 to 4.0
    • Upgrading Spree from 3.6 to 3.7
    • Upgrading Spree from 3.5 to 3.6
    • Upgrading Spree from 3.4 to 3.5
    • Upgrading Spree from 3.3 to 3.4
    • Upgrading Spree from 3.2 to 3.3
    • Upgrading Spree from 3.1 to 3.2
    • Upgrading Spree from 3.0 to 3.1

Table Of Contents

OverviewUser and RolesAbility classAdding custom permissionsReplacing all permissions

Permissions

Overview

User and Roles

Spree by default comes with admin and user roles. You can create more roles in the Admin Panel UI or rails console / seed, eg.:

Spree::Role.find_or_create_by(name: 'customer_service')

Same with assigning a role, you can do it in the Admin Panel or from the console:

Spree.user_class.find_by(email: '[email protected]').spree_roles << Spree::Role.find_or_create_by(name: 'customer_service')

Ability class

For authorization Spree uses CanCanCan. The main ability class by default is Spree::Ability.

Adding custom permissions

Let’s assume you would like to add a new Role customer_service with some limited access to Admin Panel (only Orders section).

Create a new file called app/models/my_project/customer_service_ability.rb

module MyProject
  class CustomerServiceAbility
    include CanCan::Ability

    def initialize(user)
      if user.respond_to?(:has_spree_role?) && user.has_spree_role?('customer_service')
        can :manage, ::Spree::Order
      end
    end
  end
end

Please familiarize yourself with CanCanCan syntax to understand can/cannot methods more.

Now we need to inform Spree to use this ability, create another file app/models/my_project/spree/ability_decorator.rb with contents:

module MyProject
  module Spree
    module AbilityDecorator
      def abilities_to_register
        [CustomerServiceAbility]
      end
    end
  end
end

::Spree::Ability.prepend(MyProject::Spree::AbilityDecorator)

Replacing all permissions

As we’ve mentioned earlier, Spree uses main Ability class. But you can change that to use your own custom Ability class via Dependencies in Spree initializer (config/initializers/spree.rb), eg.

Spree::Dependencies.ability_class = 'MyProject::Ability'

Now, let’s define that new class in app/models/my_project/ability.rb

module MyProject
  class Ability < ::Spree::Ability
    def initialize(user)
      alias_cancan_delete_action

      user ||= Spree.user_class.new

      if user.respond_to?(:has_spree_role?) && user.has_spree_role?('admin')
        apply_admin_permissions(user)
        # add some more permissions here for the admin role
      else 
        if user.respond_to?(:has_spree_role?) && user.has_spree_role?(:customer_service)
          apply_customer_service_permissions(user)
        end

        apply_user_permissions(user)
      end

      protect_admin_role
    end

    protected

    def apply_customer_service_permissions(user)
      can :manage, ::Spree::Order
    end
  end
end

Now your can restart your rails server and observe new permissions being implemented in the application.

Leter permission changes should be automatically picked up in development and should not require application restarts.

Propose changes to this page
Maintained bySpree Commerce & Ruby on Rails developers© Spree Commerce. 2021 All Rights Reserved.