Module: Spree::Events

Defined in:
lib/spree/events.rb,
lib/spree/events/registry.rb,
lib/spree/events/adapters/base.rb,
app/jobs/spree/events/subscriber_job.rb,
app/serializers/spree/events/base_serializer.rb,
app/serializers/spree/events/post_serializer.rb,
app/serializers/spree/events/user_serializer.rb,
app/serializers/spree/events/asset_serializer.rb,
app/serializers/spree/events/image_serializer.rb,
app/serializers/spree/events/order_serializer.rb,
app/serializers/spree/events/price_serializer.rb,
app/serializers/spree/events/export_serializer.rb,
app/serializers/spree/events/import_serializer.rb,
app/serializers/spree/events/refund_serializer.rb,
app/serializers/spree/events/report_serializer.rb,
app/serializers/spree/events/digital_serializer.rb,
app/serializers/spree/events/payment_serializer.rb,
app/serializers/spree/events/product_serializer.rb,
app/serializers/spree/events/variant_serializer.rb,
app/serializers/spree/events/shipment_serializer.rb,
app/serializers/spree/events/wishlist_serializer.rb,
app/serializers/spree/events/gift_card_serializer.rb,
app/serializers/spree/events/line_item_serializer.rb,
app/serializers/spree/events/promotion_serializer.rb,
app/serializers/spree/events/import_row_serializer.rb,
app/serializers/spree/events/invitation_serializer.rb,
app/serializers/spree/events/stock_item_serializer.rb,
app/serializers/spree/events/return_item_serializer.rb,
app/serializers/spree/events/wished_item_serializer.rb,
app/serializers/spree/events/digital_link_serializer.rb,
app/serializers/spree/events/store_credit_serializer.rb,
app/serializers/spree/events/post_category_serializer.rb,
app/serializers/spree/events/reimbursement_serializer.rb,
app/serializers/spree/events/stock_movement_serializer.rb,
app/serializers/spree/events/stock_transfer_serializer.rb,
lib/spree/events/adapters/active_support_notifications.rb,
app/serializers/spree/events/customer_return_serializer.rb,
app/serializers/spree/events/gift_card_batch_serializer.rb,
app/serializers/spree/events/return_authorization_serializer.rb,
app/serializers/spree/events/newsletter_subscriber_serializer.rb

Overview

Main entry point for the Spree event system.

This module provides a clean API for publishing events and subscribing to them. It abstracts the underlying implementation (ActiveSupport::Notifications) allowing for future changes without affecting subscriber code.

Examples:

Publishing an event

Spree::Events.publish('order.completed', order.serializable_hash)

Subscribing with a class

Spree::Events.subscribe('order.completed', OrderCompletedHandler)

Subscribing with a block

Spree::Events.subscribe('order.completed') do |event|
  puts "Order completed: #{event.payload['number']}"
end

Pattern matching

Spree::Events.subscribe('order.*', OrderAuditLogger)  # All order events
Spree::Events.subscribe('*', GlobalEventLogger)       # All events

Defined Under Namespace

Modules: Adapters Classes: AssetSerializer, BaseSerializer, CustomerReturnSerializer, DigitalLinkSerializer, DigitalSerializer, ExportSerializer, GiftCardBatchSerializer, GiftCardSerializer, ImageSerializer, ImportRowSerializer, ImportSerializer, InvitationSerializer, LineItemSerializer, NewsletterSubscriberSerializer, OrderSerializer, PaymentSerializer, PostCategorySerializer, PostSerializer, PriceSerializer, ProductSerializer, PromotionSerializer, RefundSerializer, Registry, ReimbursementSerializer, ReportSerializer, ReturnAuthorizationSerializer, ReturnItemSerializer, ShipmentSerializer, StockItemSerializer, StockMovementSerializer, StockTransferSerializer, StoreCreditSerializer, SubscriberJob, UserSerializer, VariantSerializer, WishedItemSerializer, WishlistSerializer

Class Method Summary collapse

Class Method Details

.activate!Object

Activate the event system (called during Rails initialization) Also registers all subscribers from Spree.subscribers This method is idempotent - calling it multiple times has no effect



104
105
106
107
108
109
# File 'lib/spree/events.rb', line 104

def activate!
  return if registry.size > 0

  register_subscribers!
  adapter.activate!
end

.adapterObject

Get the adapter instance

The adapter class can be configured via Spree.events_adapter_class Default: Spree::Events::Adapters::ActiveSupportNotifications

Returns:

  • (Object)

    the configured adapter instance



97
98
99
# File 'lib/spree/events.rb', line 97

def adapter
  @adapter ||= Spree.events_adapter_class.new(registry)
end

.disable { ... } ⇒ Object

Temporarily disable events within a block

Examples:

Spree::Events.disable do
  # Events published here won't trigger subscribers
  order.complete!
end

Yields:

  • Block during which events are disabled

Returns:

  • (Object)

    Return value of the block



197
198
199
200
201
202
203
# File 'lib/spree/events.rb', line 197

def disable
  previous = RequestStore.store[:spree_events_disabled]
  RequestStore.store[:spree_events_disabled] = true
  yield
ensure
  RequestStore.store[:spree_events_disabled] = previous
end

.disable!void

This method returns an undefined value.

Globally disable events Useful for testing to disable events for the entire test suite



208
209
210
# File 'lib/spree/events.rb', line 208

def disable!
  RequestStore.store[:spree_events_disabled] = true
end

.enable { ... } ⇒ Object

Temporarily enable events within a block Useful for testing when events are globally disabled

Examples:

Spree::Events.enable do
  # Events published here will trigger subscribers
  order.complete!
end

Yields:

  • Block during which events are enabled

Returns:

  • (Object)

    Return value of the block



224
225
226
227
228
229
230
# File 'lib/spree/events.rb', line 224

def enable
  previous = RequestStore.store[:spree_events_disabled]
  RequestStore.store[:spree_events_disabled] = false
  yield
ensure
  RequestStore.store[:spree_events_disabled] = previous
end

.enable!void

This method returns an undefined value.

Globally enable events Useful for testing



235
236
237
# File 'lib/spree/events.rb', line 235

def enable!
  RequestStore.store[:spree_events_disabled] = false
end

.enabled?Boolean

Check if events are enabled

Events can be temporarily disabled using Spree::Events.disable { … }

Returns:

  • (Boolean)


182
183
184
# File 'lib/spree/events.rb', line 182

def enabled?
  !RequestStore.store[:spree_events_disabled]
end

.patternsArray<String>

List all registered subscriber patterns

Returns:

  • (Array<String>)


166
167
168
# File 'lib/spree/events.rb', line 166

def patterns
  registry.patterns
end

.publish(name, payload = {}, metadata = {}) ⇒ Spree::Event

Publish an event to all matching subscribers

Examples:

Spree::Events.publish('product.created', product.serializable_hash)
Spree::Events.publish('order.completed', order.serializable_hash, { user_id: current_user.id })

Parameters:

  • name (String)

    The event name (e.g., ‘order.complete’)

  • payload (Hash) (defaults to: {})

    The event payload (should be serializable)

  • metadata (Hash) (defaults to: {})

    Additional metadata for the event

Returns:



42
43
44
# File 'lib/spree/events.rb', line 42

def publish(name, payload = {},  = {})
  adapter.publish(name, payload, )
end

.register_subscribers!void

This method returns an undefined value.

Register all subscribers from Spree.subscribers

This is called automatically during Rails initialization. Can also be called in tests after reset! to re-register subscribers.

In development, class objects in Spree.subscribers may become stale after code reload (Zeitwerk creates new class objects). We resolve the constant fresh from the class name to ensure we’re using the reloaded class.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/spree/events.rb', line 128

def register_subscribers!
  return unless defined?(Spree) && Spree.respond_to?(:subscribers)

  Spree.subscribers&.each do |subscriber|
    # Resolve the subscriber constant fresh to handle code reload in development
    # The array may contain stale class objects after Zeitwerk reload
    resolved_subscriber = resolve_subscriber(subscriber)
    next unless resolved_subscriber

    resolved_subscriber.subscription_patterns.each do |pattern|
      subscribe(pattern, resolved_subscriber, resolved_subscriber.subscription_options)
    end
  end
end

.registrySpree::Events::Registry

Get the event registry



87
88
89
# File 'lib/spree/events.rb', line 87

def registry
  @registry ||= Registry.new
end

.reset!Object

Reset the event system (useful for testing)



112
113
114
115
116
# File 'lib/spree/events.rb', line 112

def reset!
  adapter.deactivate! if @adapter
  @registry = nil
  @adapter = nil
end

.resolve_subscriber(subscriber) ⇒ Class?

Resolve a subscriber to its current class object

In development, Zeitwerk may have reloaded the class, creating a new class object while the old one is still referenced in Spree.subscribers. This method resolves the constant fresh to get the current class.

Parameters:

  • subscriber (Class, String)

    The subscriber class or class name

Returns:

  • (Class, nil)

    The resolved class or nil if not found



151
152
153
154
155
156
157
158
159
160
161
# File 'lib/spree/events.rb', line 151

def resolve_subscriber(subscriber)
  return subscriber unless Rails.env.development? || Rails.env.test?

  class_name = subscriber.is_a?(String) ? subscriber : subscriber.name
  return nil unless class_name

  class_name.constantize
rescue NameError => e
  Rails.logger.warn "[Spree Events] Could not resolve subscriber #{class_name}: #{e.message}"
  nil
end

.subscribe(pattern, subscriber = nil, options = {}) {|event| ... } ⇒ void

This method returns an undefined value.

Subscribe to an event pattern

Examples:

With a subscriber class

Spree::Events.subscribe('order.completed', SendConfirmationEmail)

With a block

Spree::Events.subscribe('order.completed') { |event| puts event.name }

With pattern matching

Spree::Events.subscribe('order.*', OrderAuditLogger)

Synchronous execution

Spree::Events.subscribe('order.completed', MyHandler, async: false)

Parameters:

  • pattern (String)

    Event pattern (supports wildcards like ‘order.*’ or ‘*’)

  • subscriber (Class, Proc, nil) (defaults to: nil)

    The subscriber class or callable

  • options (Hash) (defaults to: {})

    Subscription options

Options Hash (options):

  • :async (Boolean) — default: true

    Whether to run async via ActiveJob

Yields:

  • (event)

    Block to execute when event occurs (alternative to subscriber param)

Yield Parameters:

Raises:

  • (ArgumentError)


68
69
70
71
72
73
# File 'lib/spree/events.rb', line 68

def subscribe(pattern, subscriber = nil, options = {}, &block)
  subscriber = block if block_given?
  raise ArgumentError, 'Must provide a subscriber class, callable, or block' unless subscriber

  adapter.subscribe(pattern, subscriber, options)
end

.subscriptionsArray<Spree::Events::Registry::Subscription>

List all subscriptions



173
174
175
# File 'lib/spree/events.rb', line 173

def subscriptions
  registry.all_subscriptions
end

.unsubscribe(pattern, subscriber) ⇒ Boolean

Unsubscribe from an event pattern

Parameters:

  • pattern (String)

    Event pattern

  • subscriber (Class, Proc)

    The subscriber to remove

Returns:

  • (Boolean)

    true if removed, false if not found



80
81
82
# File 'lib/spree/events.rb', line 80

def unsubscribe(pattern, subscriber)
  adapter.unsubscribe(pattern, subscriber)
end