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 V3 API serializers resolved by convention: Spree::Order → Spree::Api::V3::OrderSerializer.

Models without a V3 serializer get a minimal fallback payload:

{ id: prefixed_id, created_at: ..., updated_at: ... }

STI models (e.g., Spree::Exports::Products) can override event_serializer_class to point to the parent serializer.

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

Overriding the serializer for STI models

class Spree::Export < Spree.base_class
  def event_serializer_class
    Spree::Api::V3::ExportSerializer
  end
end

Instance Method Summary collapse

Instance Method Details

#event_contextHash

Context passed to the event serializer

Returns:

  • (Hash)


197
198
199
200
201
202
203
# File 'app/models/concerns/spree/publishable.rb', line 197

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 the V3 serializer resolved by convention. Falls back to a minimal payload if no serializer is found.

Returns:

  • (Hash)


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'app/models/concerns/spree/publishable.rb', line 151

def event_payload
  serializer = event_serializer_class

  unless serializer
    return {
      id: respond_to?(:prefixed_id) ? prefixed_id : id,
      created_at: created_at&.iso8601,
      updated_at: updated_at&.iso8601
    }
  end

  # Use as_json to ensure all values are JSON-safe primitives.
  # Alba's to_h can return raw Ruby objects (e.g., Spree::Money) which
  # ActiveJob cannot serialize for async event subscribers.
  serializer.new(self, params: event_serializer_params).to_h.as_json
end

#event_prefixString

Get the event prefix for this instance

Returns:

  • (String)


208
209
210
# File 'app/models/concerns/spree/publishable.rb', line 208

def event_prefix
  self.class.event_prefix
end

#event_serializer_classClass?

Find the event serializer class for this model

Looks for Spree::Api::V3::ModelNameSerializer by convention. Walks up the class hierarchy to support STI models.

Models can override this method to specify a custom serializer, which is useful for STI models like Export, Import, Report.

Returns:

  • (Class, nil)

    The serializer class or nil if not found



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'app/models/concerns/spree/publishable.rb', line 177

def event_serializer_class
  return nil unless self.class.name

  klass = self.class
  while klass && klass != Object && klass != BasicObject
    class_name = klass.name&.demodulize
    if class_name.present? && class_name != 'Base'
      serializer = "Spree::Api::V3::#{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:



135
136
137
138
139
140
141
142
143
# File 'app/models/concerns/spree/publishable.rb', line 135

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