@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.
|
|
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.
|
|
85
|
+
subscribes_to 'order.completed'
|
|
86
86
|
|
|
87
87
|
# Subscribe to multiple events
|
|
88
|
-
subscribes_to 'order.
|
|
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.
|
|
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.
|
|
106
|
+
subscribes_to 'order.completed', 'order.canceled', 'order.resumed'
|
|
107
107
|
|
|
108
|
-
on 'order.
|
|
109
|
-
on 'order.
|
|
110
|
-
on 'order.
|
|
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.
|
|
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 # => "
|
|
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.
|
|
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.
|
|
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.
|
|
480
|
+
it 'publishes order.completed event' do
|
|
481
481
|
expect(Spree::Events).to receive(:publish).with(
|
|
482
|
-
'order.
|
|
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.
|
|
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
|
-
|
|
15
|
+
A media record carries:
|
|
16
16
|
|
|
17
|
-
- **
|
|
18
|
-
- **Media
|
|
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
|
-
|
|
24
|
+
### Product-level Gallery
|
|
24
25
|
|
|
25
|
-
|
|
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.
|
|
82
|
+
subscribes_to 'order.completed'
|
|
83
83
|
|
|
84
|
-
on 'order.
|
|
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:
|