Documentation Index
Fetch the complete documentation index at: https://spreecommerce.org/docs/llms.txt
Use this file to discover all available pages before exploring further.
Spree uses CanCanCan for authorization. The permission system allows you to define granular access control for different user roles.
Permission Sets (Recommended)
Permission Sets provide a clean, modular way to manage permissions. Each permission set is a reusable group of permissions that can be assigned to roles.
How It Works
- Roles - Determine which permission sets govern a user’s access (e.g.,
admin, customer_service)
- Permission Sets - Contain the logic defining what actions users can perform on resources
- Role Configuration - Associates roles with their corresponding permission sets
Configuring Roles
In your config/initializers/spree.rb, configure which permission sets are assigned to each role:
Rails.application.config.after_initialize do
# Default permissions for all users (guests and logged-in customers)
Spree.permissions.assign(:default, [Spree::PermissionSets::DefaultCustomer])
# Full admin access
Spree.permissions.assign(:admin, [Spree::PermissionSets::SuperUser])
# Custom role with specific permissions
Spree.permissions.assign(:customer_service, [
Spree::PermissionSets::DashboardDisplay,
Spree::PermissionSets::OrderManagement,
Spree::PermissionSets::UserDisplay
])
# Merchandiser role for product management
Spree.permissions.assign(:merchandiser, [
Spree::PermissionSets::DashboardDisplay,
Spree::PermissionSets::ProductManagement,
Spree::PermissionSets::StockManagement
])
end
Built-in Permission Sets
| Permission Set | Description |
|---|
SuperUser | Full admin access with safety restrictions |
DefaultCustomer | Basic storefront permissions (browse, checkout, manage own account) |
DashboardDisplay | View admin dashboard |
OrderDisplay | Read-only access to orders |
OrderManagement | Full order management (view, edit, refund, etc.) |
ProductDisplay | Read-only access to products and catalog |
ProductManagement | Full catalog management (products, variants, taxonomies) |
UserDisplay | Read-only access to users |
UserManagement | Full user management |
StockDisplay | Read-only access to inventory |
StockManagement | Full inventory management |
PromotionManagement | Manage promotions and coupon codes |
ConfigurationManagement | Manage store settings, shipping, taxes, etc. |
RoleManagement | Manage roles (except the protected admin role) |
Creating Custom Permission Sets
Create a new permission set in app/models/spree/permission_sets/:
# app/models/spree/permission_sets/warehouse_management.rb
module Spree
module PermissionSets
class WarehouseManagement < Base
def activate!
can :manage, Spree::StockItem
can :manage, Spree::StockLocation
can :manage, Spree::StockMovement
can :manage, Spree::Shipment
can [:read, :admin], Spree::Order
end
end
end
end
Then assign it to a role:
Spree.permissions.assign(:warehouse_staff, [
Spree::PermissionSets::DashboardDisplay,
Spree::PermissionSets::WarehouseManagement
])
Permission Set API
Within a permission set, you have access to:
can(action, subject, conditions = {}) - Grant permission
cannot(action, subject, conditions = {}) - Deny permission
can?(action, subject) - Check if permission exists
user - The current user
store - The current store (for multi-store setups)
module Spree
module PermissionSets
class OrderManagementForOwnOrders < Base
def activate!
# Users can only manage orders they created
can :manage, Spree::Order, created_by_id: user.id
# But cannot cancel any order
cannot :cancel, Spree::Order
# Unless it's cancellable
can :cancel, Spree::Order, &:allow_cancel?
end
end
end
end
Managing Permission Configuration
# Assign permission sets to a role
Spree.permissions.assign(:customer_service, [
Spree::PermissionSets::OrderDisplay,
Spree::PermissionSets::UserManagement
])
# Add more permission sets to an existing role
Spree.permissions.assign(:customer_service, [
Spree::PermissionSets::StockDisplay
])
# Clear all permission sets from a role
Spree.permissions.clear(:customer_service)
# Check what permission sets a role has
Spree.permissions.permission_sets_for(:customer_service)
# => [Spree::PermissionSets::OrderDisplay, ...]
# Check if a role is configured
Spree.permissions.role_configured?(:customer_service)
# => true
Users and Roles
Spree comes with an admin role by default. You can create more roles in the Admin Panel or via Rails console:
Spree::Role.find_or_create_by(name: 'customer_service')
Spree::Role.find_or_create_by(name: 'merchandiser')
Spree::Role.find_or_create_by(name: 'warehouse_staff')
Assign a role to a user:
user = Spree.user_class.find_by(email: 'john@example.com')
role = Spree::Role.find_by(name: 'customer_service')
user.spree_roles << role
Default Role Behavior
- Users with no roles assigned automatically get the
:default role permissions
- No
RoleUser records are created for regular customers
- Only users with special permissions need explicit role assignments
Legacy Approach: Custom Ability Classes
The permission sets approach above is recommended for new projects. The legacy approach below is supported for backward compatibility.
Adding Custom Permissions via Decorator
Create a new ability class in app/models/customer_service_ability.rb:
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
Register it via a decorator in app/models/spree/ability_decorator.rb:
module Spree
module AbilityDecorator
def abilities_to_register
[CustomerServiceAbility]
end
end
Ability.prepend(AbilityDecorator)
end
Replacing the Ability Class
You can replace the entire ability class via Dependencies:
# config/initializers/spree.rb
Spree::Dependencies.ability_class = 'CustomAbility'
# app/models/custom_ability.rb
class CustomAbility < Spree::Ability
def initialize(user, options = {})
alias_cancan_delete_action
@user = user || Spree.user_class.new
@store = options[:store] || Spree::Current.store
if @user.respond_to?(:has_spree_role?) && @user.has_spree_role?('admin')
apply_admin_permissions(@user, options)
elsif @user.respond_to?(:has_spree_role?) && @user.has_spree_role?(:customer_service)
apply_customer_service_permissions(@user)
else
apply_user_permissions(@user, options)
end
protect_admin_role
end
protected
def apply_customer_service_permissions(user)
can :manage, Spree::Order
can [:read, :admin], Spree.user_class
end
end
CanCanCan Reference
Spree’s permission system is built on CanCanCan. Key concepts:
can :action, Subject - Grant permission
can :manage, Subject - Grant all actions (create, read, update, destroy)
cannot :action, Subject - Explicitly deny permission
can :action, Subject, conditions - Conditional permission
# Examples
can :read, Spree::Product # Can read any product
can :manage, Spree::Order, user_id: user.id # Can manage own orders
can :update, Spree::Order do |order| # Block conditions
order.user == user && !order.completed?
end
cannot :destroy, Spree::Order # Cannot destroy any order
can :destroy, Spree::Order, &:can_be_deleted? # Unless it's deletable
See the CanCanCan documentation for more details.