@spree/docs 0.1.291 → 0.1.293

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.
@@ -14,12 +14,14 @@ store.save
14
14
 
15
15
  To define a model preference, you need to add them to your model class.
16
16
 
17
- Make sure to generate a migration to add the `preferences` column to the table. This column will store the preferences in a serialized format.
17
+ Make sure to generate a migration to add the `preferences` column to the table. This column stores the preferences as JSON.
18
18
 
19
19
  ```bash
20
- spree generate migration AddPreferencesToSpreeBrands preferences:text
20
+ spree generate migration AddPreferencesToSpreeBrands preferences:jsonb
21
21
  ```
22
22
 
23
+ `jsonb` is for PostgreSQL, the default database. On MySQL or SQLite use `preferences:json`.
24
+
23
25
  Run the migration.
24
26
 
25
27
  ```bash
@@ -90,7 +92,28 @@ You can get a hash of all stored preferences by accessing the `preferences` help
90
92
  brand.preferences # => { 'featured' => false, 'display_name' => 'Wilson' }
91
93
  ```
92
94
 
93
- This hash will contain the value for every preference that has been defined for the model instance, whether the value is the default or one that has been previously stored.
95
+ This hash will contain the value for every preference that has been defined for the model instance, whether the value is the default or one that has been previously stored. Its keys are strings, and it can be read with either strings or symbols (`brand.preferences[:featured]`). Values are stored as JSON, so read typed values through the `preferred_*` methods: a `:decimal` preference comes back as a `BigDecimal` there, while the raw hash holds its exact string (`"9.99"`).
96
+
97
+ `preferences` never holds secrets — see [Secret preferences](#secret-preferences).
98
+
99
+ ## Secret preferences
100
+
101
+ Declare API keys, signing secrets and other credentials with the `:password` type:
102
+
103
+ ```ruby server/app/models/my_app/gateway.rb
104
+ module MyApp
105
+ class Gateway < Spree::Gateway
106
+ preference :publishable_key, :string
107
+ preference :secret_key, :password
108
+ end
109
+ end
110
+ ```
111
+
112
+ A `:password` preference works like any other — `preferred_secret_key`, `preferred_secret_key = ...`, `get_preference(:secret_key)` — but it is stored apart from the other preferences, in an encrypted `secret_preferences` column, whenever [Active Record encryption keys](../deployment/environment_variables.md#active-record-encryption) are configured. The Admin API returns it masked, showing only its last four characters.
113
+
114
+ Payment methods and integrations already have that column. To declare a secret on another model, include `Spree::SecretPreferences` and add a `secret_preferences` text column to its table; Spree refuses a `:password` preference on a model that cannot encrypt it.
115
+
116
+ Always declare a credential as `:password`. A secret declared as `:string`, or nested inside a `:hash` or `:array` preference, is stored in plain text.
94
117
 
95
118
  ## Models with preferences
96
119
 
@@ -18,7 +18,7 @@ You'll almost always want to set [`RAILS_HOST`](#urls-and-hosts) too — without
18
18
 
19
19
  ## Active Record encryption
20
20
 
21
- Spree encrypts sensitive values at rest with [Active Record encryption](https://guides.rubyonrails.org/active_record_encryption.html): webhook endpoint signing secrets, payment gateway customer IDs, and the OAuth tokens stored on user identities. It does so only when encryption keys are configured — without them, these values are stored in plain text and a production app logs a warning at boot.
21
+ Spree encrypts sensitive values at rest with [Active Record encryption](https://guides.rubyonrails.org/active_record_encryption.html): payment gateway and integration secrets (API keys and webhook signing secrets), webhook endpoint signing secrets, payment gateway customer IDs, and the OAuth tokens stored on user identities. It does so only when encryption keys are configured — without them, these values are stored in plain text and a production app logs a warning at boot.
22
22
 
23
23
  | Variable | Description |
24
24
  | --- | --- |
@@ -33,6 +33,8 @@ module SpreeAcmeCarrier
33
33
  preference :test_mode, :boolean, default: true
34
34
 
35
35
  def self.integration_group = 'shipping'
36
+ def self.logo_url = 'https://acme-carrier.example.com/logo.svg'
37
+ def self.docs_url = 'https://acme-carrier.example.com/docs/spree'
36
38
 
37
39
  # Called when an admin activates the integration. Returning false blocks
38
40
  # activation and shows your message in the dashboard.
@@ -51,6 +53,8 @@ module SpreeAcmeCarrier
51
53
  end
52
54
  ```
53
55
 
56
+ `logo_url` and `docs_url` are optional. They put your logo and a "Setup guide" link on the integration's card under **Settings > Integrations**. Payment methods declare them the same way.
57
+
54
58
  Declare secrets as `:password` preferences. Spree masks them on read and guards the round-trip on write, so an API key never leaves the server in plain text.
55
59
 
56
60
  ## 2. Implement the provider
@@ -43,6 +43,30 @@ end
43
43
 
44
44
  After restarting your server, you can select "MyGateway" when creating a new payment method in the admin panel under **Settings > Payments**.
45
45
 
46
+ ### Show a logo and setup guide (optional)
47
+
48
+ Payment methods backed by an external provider also appear in the admin dashboard under **Settings > Integrations**, next to other connected services. A method is listed there when it inherits from `Spree::Gateway`, or when its class defines `self.third_party?` to return `true`. Declare a logo and a link to your setup guide so merchants recognise the provider and know how to connect it:
49
+
50
+ ```ruby app/models/my_gateway.rb
51
+ class MyGateway < Spree::PaymentMethod
52
+ # Lists MyGateway under Settings > Integrations. Not needed when the class
53
+ # inherits from Spree::Gateway.
54
+ def self.third_party?
55
+ true
56
+ end
57
+
58
+ def self.logo_url
59
+ 'https://my-gateway.example.com/logo.svg'
60
+ end
61
+
62
+ def self.docs_url
63
+ 'https://my-gateway.example.com/docs/spree'
64
+ end
65
+ end
66
+ ```
67
+
68
+ `logo_url` accepts anything an image tag accepts, including a `data:` URI if you don't want to host the file. Both are optional: without a logo the card shows the provider's first letter, and without a guide the link is hidden. Integrations declare the same two methods — see [custom delivery rate providers](custom-delivery-rate-provider.md).
69
+
46
70
  ## Step 3: Add Payment Session Support
47
71
 
48
72
  Payment Sessions are the modern, PCI-compliant way to handle payments. Your gateway creates a session with the provider, the frontend collects payment details using the provider's SDK, and Spree records the result.
@@ -49,6 +49,24 @@ Re-running is safe — `bundle exec rake spree:upgrade` figures out what still n
49
49
 
50
50
  Reference material — the data backfills `bundle exec rake spree:upgrade` executes. Every task is idempotent.
51
51
 
52
+ ### Store preferences as JSON
53
+
54
+
55
+ ```bash Spree CLI (Docker)
56
+ spree rake spree:upgrade:preferences_json
57
+ spree rake spree:upgrade:encrypt_secret_preferences
58
+ ```
59
+
60
+ ```bash Without Spree CLI
61
+ bundle exec rake spree:upgrade:preferences_json
62
+ bundle exec rake spree:upgrade:encrypt_secret_preferences
63
+ ```
64
+
65
+
66
+ Preferences were stored as YAML; in 6.0 they are JSON. The migration converts every `preferences` column itself, and moves gateway and integration secrets (preferences declared as `:password`) into a new `secret_preferences` column. The first task is a safety net for anything the migration could not reach — a schema changed by hand, or an extension gem installed after the migration ran. The second encrypts the moved secrets; until it runs they stay readable and are encrypted the next time their payment method or integration is saved. It does nothing until [encryption keys](#enable-active-record-encryption) are configured.
67
+
68
+ See [Preferences are stored as JSON](#preferences-are-stored-as-json) for what changes in your code.
69
+
52
70
  ### Convert incomplete orders into carts
53
71
 
54
72
  ```bash
@@ -181,7 +199,7 @@ Countries and states are no longer database records in 6.0. Addresses, delivery
181
199
 
182
200
  ## Enable Active Record encryption
183
201
 
184
- Spree encrypts webhook endpoint signing secrets, payment gateway customer IDs and the OAuth tokens on user identities with [Active Record encryption](https://guides.rubyonrails.org/active_record_encryption.html) — but only when encryption keys are configured. Without keys these values are stored in plain text. New 6.0 projects get keys at setup; upgraded applications need to add them.
202
+ Spree encrypts payment gateway and integration secrets, webhook endpoint signing secrets, payment gateway customer IDs and the OAuth tokens on user identities with [Active Record encryption](https://guides.rubyonrails.org/active_record_encryption.html) — but only when encryption keys are configured. Without keys these values are stored in plain text. New 6.0 projects get keys at setup; upgraded applications need to add them.
185
203
 
186
204
  **1. Make the app read the keys.** Projects created from `spree-starter` read them from the `ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY`, `ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY` and `ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT` env vars, falling back to the `active_record_encryption` entry in Rails credentials. If your `config/application.rb` predates this, add inside the `Application` class:
187
205
 
@@ -212,7 +230,31 @@ Recreate the containers so they pick up the new `.env` (`spree update`, or `spre
212
230
 
213
231
  > **WARNING:** Never change or lose the keys once data is encrypted — the encrypted records become unreadable.
214
232
 
215
- **3. Encrypt existing rows.** Rows written before the keys were set are plain text. OAuth tokens on user identities stay readable and are encrypted on their next write. Webhook endpoint secrets and gateway customer IDs can't be read in plain text once encryption is on — follow [Enabling encryption on an existing installation](../deployment/environment_variables.md#enabling-encryption-on-an-existing-installation): turn on `support_unencrypted_data` and `extend_queries`, deploy with the keys, run `find_each(&:encrypt)` over `Spree::WebhookEndpoint`, `Spree::GatewayCustomer` and `Spree::UserIdentity`, then turn the two settings off again.
233
+ **3. Encrypt existing rows.** Rows written before the keys were set are plain text. Gateway and integration secrets and the OAuth tokens on user identities stay readable and are encrypted on their next write; run `spree rake spree:upgrade:encrypt_secret_preferences` (`bundle exec rake spree:upgrade:encrypt_secret_preferences` without the Spree CLI) to encrypt every gateway and integration secret at once. Webhook endpoint secrets and gateway customer IDs can't be read in plain text once encryption is on — follow [Enabling encryption on an existing installation](../deployment/environment_variables.md#enabling-encryption-on-an-existing-installation): turn on `support_unencrypted_data` and `extend_queries`, deploy with the keys, run `find_each(&:encrypt)` over `Spree::WebhookEndpoint`, `Spree::GatewayCustomer` and `Spree::UserIdentity`, then turn the two settings off again.
234
+
235
+ ## Preferences are stored as JSON
236
+
237
+ Model preferences moved from YAML to JSON, and secrets moved out of them. Declarations do not change, and the `preferred_*` methods return the same values as before. What can affect your code:
238
+
239
+ - **The raw `preferences` hash has string keys.** It still answers to symbols (`calculator.preferences[:amount]`), but `preferences.keys` returns strings. Decimals sit in it as exact strings (`"9.99"`); read them through `preferred_*`, which returns a `BigDecimal`.
240
+ - **Secrets are not in `preferences`.** Preferences declared `:password` live in the encrypted `secret_preferences` column. Read them with `preferred_*` or `get_preference`. A secret you assign as part of a whole hash (`update(preferences: { secret_key: ... })`) is moved there when the record is saved. To declare a secret on a model other than a payment method or an integration, see [Secret preferences](../customization/model-preferences.md#secret-preferences).
241
+ - **Your own preference tables need a JSON column.** The migration converts every table a model storing Spree preferences reads, including your application's own; a table another library owns is left alone. A new table should use `t.jsonb :preferences` on PostgreSQL, the default database (`t.json` on MySQL or SQLite).
242
+ - **Tiered calculators take a list of tiers.** `Spree::Calculator::TieredPercent` and `TieredFlatRate` store `tiers` as a list instead of a hash keyed by threshold, in Ruby and in the Admin API. The migration converts existing calculators.
243
+
244
+ ```json
245
+ // Before
246
+ { "tiers": { "100": 10, "250": 15 } }
247
+ // After
248
+ { "tiers": [{ "threshold": "100", "value": "10" }, { "threshold": "250", "value": "15" }] }
249
+ ```
250
+
251
+ `value` is a percentage for `TieredPercent` and an amount for `TieredFlatRate`.
252
+ - **Spree no longer allows extra classes in YAML columns.** It used to add `Symbol`, `BigDecimal` and a few time classes to `config.active_record.yaml_column_permitted_classes`. If your application serializes its own columns as YAML with those classes, add them in `config/application.rb` yourself.
253
+ - **Preference change methods follow Rails' naming.** Each preference is a Rails store accessor, so `preferred_<name>_changed?`, `preferred_<name>_change` and `preferred_<name>_was` work as before, while the after-save forms are Rails' own: `saved_change_to_preferred_<name>?` replaces `preferred_<name>_previously_changed?`, `saved_change_to_preferred_<name>` replaces `preferred_<name>_previous_change`, and `preferred_<name>_before_last_save` replaces `preferred_<name>_previously_was`.
254
+ - **Per-preference helper methods are gone.** Use `preference_type(:name)`, `preference_default(:name)` and `preference_deprecated(:name)` instead of `preferred_<name>_type`, `preferred_<name>_default` and `preferred_<name>_deprecated`. `clear_preferences`, `restore_preferences_for`, `preferences_of_type`, the class methods `preference_getter_method`, `preference_setter_method` and `prefers_query_method`, `Spree::Preferences::ScopedStore`, `Spree::Preferences::Store` and the `Spree::Preference` model are removed.
255
+ - **The `spree_preferences` table is dropped.** The installation id it held is not carried over: the default store generates a new one the next time it is saved. Rows an application wrote there itself are dropped with it: copy any you need before upgrading.
256
+ - **Preferences live only on models.** `Spree::Preferences::Preferable` is included by `Spree::Base` and needs a `preferences` JSON column; including it in a plain Ruby class is no longer supported. A hash stored inside a preference comes back with string keys.
257
+ - **A record whose preferences still hold YAML cannot be read.** The migration converts every row, so this only happens to rows written by older code after it ran. Run `spree rake spree:upgrade:preferences_json` (`bundle exec rake spree:upgrade:preferences_json` without the Spree CLI) to convert it.
216
258
 
217
259
  ## The Cart/Order split
218
260
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spree/docs",
3
- "version": "0.1.291",
3
+ "version": "0.1.293",
4
4
  "description": "Spree Commerce developer documentation for AI agents and local reference",
5
5
  "type": "module",
6
6
  "license": "CC-BY-4.0",