Module: Spree::Publishable

Extended by:
ActiveSupport::Concern
Included in:
Base, UserMethods
Defined in:
app/models/concerns/spree/publishable.rb

Overview

Concern for models that publish events.

This concern is included in Spree::Base, so all Spree models can emit events. Event payloads are generated using dedicated serializers from the Spree::Events namespace.

Examples:

Disabling events for a specific model

class Spree::LogEntry < Spree.base_class
  self.publish_events = false
end

Publishing custom events

class Spree::Order < Spree.base_class
  def complete!
    # ... completion logic ...
    publish_event('order.completed')
  end
end

Creating an event serializer (required for each model that publishes events)

# app/serializers/spree/events/order_serializer.rb
class Spree::Events::OrderSerializer < Spree::Events::BaseSerializer
  protected

  def attributes
    {
      id: resource.id,
      number: resource.number,
      state: resource.state.to_s,
      # ... other attributes
    }
  end
end

Defined Under Namespace

Classes: MissingSerializerError

Instance Method Summary collapse

Instance Method Details

#event_contextHash

Context passed to the event serializer

Returns:

  • (Hash)


213
214
215
216
217
218
219
# File 'app/models/concerns/spree/publishable.rb', line 213

def event_context
  {
    event_name: @_current_event_name,
    store_id: Spree::Current.store&.id,
    triggered_at: Time.current
  }
end

#event_payloadHash

Get the payload for events

Uses dedicated event serializer (Spree::Events::ModelSerializer). Raises MissingSerializerError if no serializer is defined.

Returns:

  • (Hash)

Raises:



176
177
178
179
180
181
182
# File 'app/models/concerns/spree/publishable.rb', line 176

def event_payload
  serializer = event_serializer_class

  raise MissingSerializerError, self.class unless serializer

  serializer.serialize(self, event_context)
end

#event_prefixString

Get the event prefix for this instance

Returns:

  • (String)


224
225
226
# File 'app/models/concerns/spree/publishable.rb', line 224

def event_prefix
  self.class.event_prefix
end

#event_serializer_classClass?

Find the event serializer class for this model

Looks for Spree::Events::ModelNameSerializer (e.g., Spree::Events::OrderSerializer) Also walks up the class hierarchy to find a serializer for parent classes. This allows subclasses like Spree::Exports::Products to use ExportSerializer.

Returns:

  • (Class, nil)

    The serializer class or nil if not found



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'app/models/concerns/spree/publishable.rb', line 191

def event_serializer_class
  return nil unless self.class.name

  # Try this class and walk up the hierarchy
  klass = self.class
  while klass && klass != Object && klass != BasicObject
    class_name = klass.name&.demodulize
    # Skip looking for BaseSerializer - that's the parent class for all serializers
    if class_name.present? && class_name != 'Base'
      serializer = "Spree::Events::#{class_name}Serializer".safe_constantize
      return serializer if serializer
    end

    klass = klass.superclass
  end

  nil
end

#publish_event(event_name, payload = nil, metadata = {}) ⇒ Spree::Event

Publish an event with this model’s data

Examples:

order.publish_event('order.completed')
order.publish_event('order.completed', { custom: 'data' })
order.publish_event('order.completed', metadata: { user_id: 1 })

Parameters:

  • event_name (String)

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

  • payload (Hash, nil) (defaults to: nil)

    Custom payload (defaults to event_payload)

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

    Additional metadata

Returns:



159
160
161
162
163
164
165
166
167
# File 'app/models/concerns/spree/publishable.rb', line 159

def publish_event(event_name, payload = nil,  = {})
  return unless Spree::Events.enabled?

  @_current_event_name = event_name
  payload ||= event_payload
  Spree::Events.publish(event_name, payload, )
ensure
  @_current_event_name = nil
end