@spree/docs 0.1.48 → 0.1.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61,7 +61,7 @@ Create a subscriber class in `app/subscribers/` that inherits from `Spree::Subsc
61
61
  ```ruby app/subscribers/my_app/order_completed_subscriber.rb
62
62
  module MyApp
63
63
  class OrderCompletedSubscriber < Spree::Subscriber
64
- subscribes_to 'order.complete'
64
+ subscribes_to 'order.completed'
65
65
 
66
66
  def handle(event)
67
67
  order_id = event.payload['id']
@@ -82,17 +82,17 @@ The `Spree::Subscriber` class provides a clean DSL for declaring subscriptions:
82
82
  ```ruby
83
83
  class MySubscriber < Spree::Subscriber
84
84
  # Subscribe to a single event
85
- subscribes_to 'order.complete'
85
+ subscribes_to 'order.completed'
86
86
 
87
87
  # Subscribe to multiple events
88
- subscribes_to 'order.complete', 'order.cancel', 'order.resume'
88
+ subscribes_to 'order.completed', 'order.canceled', 'order.resumed'
89
89
 
90
90
  # Subscribe to all events matching a pattern
91
91
  subscribes_to 'order.*' # All order events
92
92
  subscribes_to '*.*' # All events (use sparingly!)
93
93
 
94
94
  # Run synchronously instead of via background job
95
- subscribes_to 'order.complete', async: false
95
+ subscribes_to 'order.completed', async: false
96
96
  end
97
97
  ```
98
98
 
@@ -103,11 +103,11 @@ When subscribing to multiple events, use the `on` DSL to route events to specifi
103
103
  ```ruby app/subscribers/my_app/order_audit_subscriber.rb
104
104
  module MyApp
105
105
  class OrderAuditSubscriber < Spree::Subscriber
106
- subscribes_to 'order.complete', 'order.cancel', 'order.resume'
106
+ subscribes_to 'order.completed', 'order.canceled', 'order.resumed'
107
107
 
108
- on 'order.complete', :log_order_completed
109
- on 'order.cancel', :log_order_canceled
110
- on 'order.resume', :log_order_resumed
108
+ on 'order.completed', :log_order_completed
109
+ on 'order.canceled', :log_order_canceled
110
+ on 'order.resumed', :log_order_resumed
111
111
 
112
112
  private
113
113
 
@@ -144,7 +144,7 @@ When your subscriber receives an event, you get a `Spree::Event` object with:
144
144
  ```ruby
145
145
  def handle(event)
146
146
  event.id # => "550e8400-e29b-41d4-a716-446655440000" (UUID)
147
- event.name # => "order.complete"
147
+ event.name # => "order.completed"
148
148
  event.store_id # => 1 (ID of the store where the event originated)
149
149
  event.payload # => { "id" => 1, "number" => "R123456", ... }
150
150
  event.metadata # => { "spree_version" => "5.1.0" }
@@ -153,7 +153,7 @@ def handle(event)
153
153
  # Helper methods
154
154
  event.store # => Spree::Store instance (lazy loaded)
155
155
  event.resource_type # => "order" (extracted from name)
156
- event.action # => "complete" (extracted from name)
156
+ event.action # => "completed" (extracted from name)
157
157
  end
158
158
  ```
159
159
 
@@ -421,7 +421,7 @@ For critical operations that must complete before the request finishes, use sync
421
421
 
422
422
  ```ruby
423
423
  class CriticalOrderHandler < Spree::Subscriber
424
- subscribes_to 'order.complete', async: false
424
+ subscribes_to 'order.completed', async: false
425
425
 
426
426
  def handle(event)
427
427
  # This runs immediately, blocking the request
@@ -458,7 +458,7 @@ RSpec.describe MyApp::OrderCompletedSubscriber do
458
458
  let(:order) { create(:completed_order_with_totals) }
459
459
  let(:event) do
460
460
  Spree::Event.new(
461
- name: 'order.complete',
461
+ name: 'order.completed',
462
462
  payload: order.event_payload
463
463
  )
464
464
  end
@@ -477,9 +477,9 @@ end
477
477
  Use the `emit_webhook_event` matcher (if available) or stub the events:
478
478
 
479
479
  ```ruby
480
- it 'publishes order.complete event' do
480
+ it 'publishes order.completed event' do
481
481
  expect(Spree::Events).to receive(:publish).with(
482
- 'order.complete',
482
+ 'order.completed',
483
483
  hash_including('id' => order.id)
484
484
  )
485
485
 
@@ -506,7 +506,7 @@ Here's a complete example of a subscriber that sends alerts when inventory is lo
506
506
  ```ruby app/subscribers/my_app/inventory_alert_subscriber.rb
507
507
  module MyApp
508
508
  class InventoryAlertSubscriber < Spree::Subscriber
509
- subscribes_to 'stock_item.update'
509
+ subscribes_to 'stock_item.updated'
510
510
 
511
511
  LOW_STOCK_THRESHOLD = 10
512
512
 
@@ -12,17 +12,74 @@ Spree handles uploads, processing, and delivery for product media. Images are au
12
12
 
13
13
  ## Product Media
14
14
 
15
- Product media uses the `Spree::Asset` model, which provides:
15
+ A media record carries:
16
16
 
17
- - **Multiple media per product** with ordering
18
- - **Media types** — `image`, `video`, `external_video`
17
+ - **Position** for ordering within the gallery
18
+ - **Media type** — `image`, `video`, or `external_video` (defaults to `image`)
19
19
  - **Alt text** for accessibility and SEO
20
20
  - **Focal point** coordinates for smart cropping
21
21
  - **Preprocessed named variants** for fast delivery
22
+ - **`variant_ids`** — which product variants the media represents. An empty array means it represents the product as a whole.
22
23
 
23
- Each media item has a `media_type` field that defaults to `image`. The `variant_ids` field indicates which product variants the media is associated with — an empty array means the media belongs to the product as a whole.
24
+ ### Product-level Gallery
24
25
 
25
- > **NOTE:** `Spree::Image` is a backward-compatible subclass of `Spree::Asset` that sets `media_type` to `image`. New code should use `Spree::Asset` directly.
26
+ In Spree 5.5 the **product** is the default owner of media. Before 5.5, every image was pinned to a specific variant (usually the master), and sharing the same image across variants meant re-uploading the file. From 5.5 onward, an image lives on the product, and any subset of variants can reference it through `variant_ids` — without duplicating the underlying file.
27
+
28
+ #### Uploading a product-level image
29
+
30
+
31
+ ```typescript Admin SDK
32
+ import { createAdminClient } from '@spree/admin-sdk'
33
+
34
+ const client = createAdminClient({ baseUrl, secretKey })
35
+
36
+ // `signed_id` comes from a direct upload; see the Active Storage docs for
37
+ // generating one client-side.
38
+ const media = await client.products.media.create('prod_86Rf07xd4z', {
39
+ signed_id: signedBlobId,
40
+ alt: 'Front view',
41
+ position: 1,
42
+ })
43
+ ```
44
+
45
+ ```bash cURL
46
+ curl -X POST 'https://api.mystore.com/api/v3/admin/products/prod_86Rf07xd4z/media' \
47
+ -H 'X-Spree-API-Key: sk_xxx' \
48
+ -H 'Content-Type: application/json' \
49
+ -d '{
50
+ "signed_id": "<signed-blob-id>",
51
+ "alt": "Front view",
52
+ "position": 1
53
+ }'
54
+ ```
55
+
56
+
57
+ #### Sharing a single image across variants
58
+
59
+ Pass a `variant_ids` array on the same media endpoint to link/unlink variants. The server replaces the asset's link set on every call — empty array clears all links, omitting the field leaves them untouched.
60
+
61
+
62
+ ```typescript Admin SDK
63
+ await client.products.media.update('prod_86Rf07xd4z', 'media_k5nR8xLq', {
64
+ variant_ids: ['variant_redM', 'variant_redL'],
65
+ })
66
+ ```
67
+
68
+ ```bash cURL
69
+ curl -X PATCH 'https://api.mystore.com/api/v3/admin/products/prod_86Rf07xd4z/media/media_k5nR8xLq' \
70
+ -H 'X-Spree-API-Key: sk_xxx' \
71
+ -H 'Content-Type: application/json' \
72
+ -d '{ "variant_ids": ["variant_redM", "variant_redL"] }'
73
+ ```
74
+
75
+
76
+ Variants belonging to a different product are silently dropped — the API rejects cross-product tampering at the model layer. Reordering happens once on the product gallery; every linked variant inherits the new order.
77
+
78
+ #### Storefront gallery resolution
79
+
80
+ The Store API's `media` field on a product returns its gallery — product-level media when present, falling back to legacy variant-pinned images during the transition. On a variant, `media` returns the assets linked to that variant via `variant_ids`, falling back to direct variant uploads.
81
+
82
+ This dual rendering means existing storefronts keep working during the upgrade; new uploads attach to the product, and you opt into a [one-shot migration](../upgrades/5.4-to-5.5.md) to re-home legacy variant-pinned data when convenient.
26
83
 
27
84
  ### Named Variant Sizes
28
85
 
@@ -134,8 +191,9 @@ curl 'https://api.mystore.com/api/v3/store/products/spree-tote?expand=media,vari
134
191
  | `focal_point_x` | number \| null | Horizontal focal point (0.0–1.0) |
135
192
  | `focal_point_y` | number \| null | Vertical focal point (0.0–1.0) |
136
193
  | `external_video_url` | string \| null | External video URL (YouTube/Vimeo) |
137
- | `original_url` | string \| null | Full-size image URL |
194
+ | `original_url` | string \| null | Full-size image URL (inline disposition) |
138
195
  | `mini_url` ... `xlarge_url` | string \| null | Named variant URLs |
196
+ | `download_url` | string \| null | Same blob as `original_url` but with `Content-Disposition: attachment`. Admin API only. |
139
197
 
140
198
  ## Image Processing
141
199
 
@@ -79,9 +79,9 @@ If you previously added Subscribers for Events, eg. `order.completed` with code
79
79
  ```ruby
80
80
  module MyApp
81
81
  class OrderAuditSubscriber < Spree::Subscriber
82
- subscribes_to 'order.complete'
82
+ subscribes_to 'order.completed'
83
83
 
84
- on 'order.complete', :log_order_completed
84
+ on 'order.completed', :log_order_completed
85
85
 
86
86
  private
87
87
 
@@ -19,6 +19,24 @@ description: This guide covers upgrading a Spree 5.4 application to Spree 5.5.
19
19
  bin/rake spree:install:migrations && bin/rails db:migrate
20
20
  ```
21
21
 
22
+ ### Migrate legacy variant-pinned media
23
+
24
+ In 5.5 the [product is the default owner of media](../core-concepts/media.md#product-level-gallery). Existing variant-pinned images keep rendering, but new admin uploads attach to the product. To consolidate both into a single gallery, run:
25
+
26
+ ```bash
27
+ bin/rails spree:media:migrate_master_images_to_product_media
28
+ ```
29
+
30
+ The task enqueues one `Spree::Media::MigrateProductAssetsJob` per product onto the `images` queue — make sure your job runner is processing that queue. Each job is idempotent, so re-running the task is safe; it skips products that no longer have variant-pinned assets.
31
+
32
+ For larger catalogs, tune the batching with `BATCH_SIZE`:
33
+
34
+ ```bash
35
+ bin/rails spree:media:migrate_master_images_to_product_media BATCH_SIZE=1000
36
+ ```
37
+
38
+ > **WARNING:** Run the task locally and on production. It does not block storefront rendering — new uploads attach to the product immediately — but until the enqueued jobs finish, old assets remain pinned to variants.
39
+
22
40
  ### Run the channels upgrade
23
41
 
24
42
  Spree 5.5 promotes `Order#channel` from a free-text string column to a real `Spree::Channel` FK. **Run this rake task immediately after `db:migrate`** — it seeds the channel rows your existing stores need and backfills `spree_orders.channel_id` from the legacy string column:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spree/docs",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
4
4
  "description": "Spree Commerce developer documentation for AI agents and local reference",
5
5
  "type": "module",
6
6
  "license": "CC-BY-4.0",