@spree/docs 0.1.85 → 0.1.86
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.
- package/dist/api-reference/admin-api/introduction.md +0 -12
- package/dist/developer/agentic/agent-skills.md +64 -0
- package/dist/developer/agentic/llm-docs.md +55 -0
- package/dist/developer/agentic/mcp.md +75 -0
- package/dist/developer/agentic/overview.md +31 -0
- package/dist/developer/cli/quickstart.md +5 -0
- package/dist/developer/contributing/developing-spree.md +2 -4
- package/dist/developer/core-concepts/events.md +80 -74
- package/dist/developer/customization/api.md +2 -2
- package/dist/developer/customization/checkout.md +11 -13
- package/dist/developer/customization/decorators.md +11 -13
- package/dist/developer/customization/quickstart.md +8 -10
- package/dist/developer/getting-started/quickstart.md +11 -0
- package/dist/developer/sdk/extending.md +1 -1
- package/dist/developer/sdk/quickstart.md +4 -0
- package/dist/developer/tutorial/admin.md +87 -17
- package/dist/developer/tutorial/{store-api.md → api.md} +118 -14
- package/dist/developer/tutorial/events.md +166 -0
- package/dist/developer/tutorial/extending-models.md +26 -22
- package/dist/developer/tutorial/introduction.md +30 -22
- package/dist/developer/tutorial/model.md +80 -19
- package/dist/developer/tutorial/sdk.md +5 -4
- package/dist/developer/tutorial/testing.md +48 -31
- package/package.json +1 -1
- package/dist/developer/tutorial/file-uploads.md +0 -121
- package/dist/developer/tutorial/rich-text.md +0 -73
|
@@ -1,36 +1,44 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Tutorial
|
|
3
3
|
sidebarTitle: Introduction
|
|
4
|
-
description:
|
|
4
|
+
description: Build a complete custom feature — model, admin UI, Store API, and TypeScript storefront integration — the Spree way.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
This tutorial walks you through creating a complete Spree feature from scratch
|
|
8
|
-
You will also learn how to extend core Spree features to connect them with your new feature.
|
|
9
|
-
By the end, you'll understand how to add new manageable features to the Spree platform.
|
|
7
|
+
This tutorial walks you through creating a complete Spree feature from scratch: a "Brands" feature that lets admins manage [Product](../core-concepts/products.md) brands, exposes them through the Store API, and consumes them from TypeScript.
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
It's written for **both backend and frontend developers**. The Ruby you'll write is minimal and mostly generated — Spree's generators produce convention-correct models, admin UIs, and API endpoints, and the TypeScript SDK gives you typed access from your storefront. You don't need to be a Rails expert to follow along.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
## Before you start
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
* Admin Dashboard controllers and views
|
|
17
|
-
* Store API endpoints and serializers
|
|
18
|
-
* TypeScript SDK integration
|
|
19
|
-
* Automated tests
|
|
13
|
+
You need a running Spree app. The fastest path is [create-spree-app](../create-spree-app/quickstart.md) — a Docker-based project with the [Spree CLI](../cli/quickstart.md), no local Ruby required:
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
```bash
|
|
16
|
+
npx create-spree-app@latest my-store
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
An existing app with Spree gems works just as well. **Every command in this tutorial is shown in two forms** — **Spree CLI** (runs inside Docker) and **Without Spree CLI** (runs directly on your machine) — pick the tab that matches your setup and ignore the other.
|
|
20
|
+
|
|
21
|
+
> **NOTE:** **create-spree-app projects:** run `spree eject` once before starting. Fresh projects use a prebuilt Docker image; ejecting switches to the dev setup that mounts `backend/` into the container, so the files the generators create land in your project (and reload live as you edit them).
|
|
22
22
|
|
|
23
|
+
> **TIP:** Using an AI coding agent? Install the [Spree agent skills](../agentic/agent-skills.md) (`npx skills add spree/agent-skills`) and connect the [docs MCP server](../agentic/mcp.md) before starting — your agent will know the conventions this tutorial teaches and can follow along with you. See [Agentic Development](../agentic/overview.md).
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
- [2. Admin Dashboard](admin.md) — Build admin interface for managing brands
|
|
26
|
-
- [3. Rich Text](rich-text.md) — Add rich text descriptions using Action Text
|
|
27
|
-
- [4. File Uploads](file-uploads.md) — Add logo images with Active Storage
|
|
28
|
-
- [5. Extending Core Models](extending-models.md) — Connect Brands to Products using associations
|
|
29
|
-
- [6. Store API](store-api.md) — Expose Brands through the Store API with serializers, controllers, and routes
|
|
30
|
-
- [7. SDK](sdk.md) — Consume Brand endpoints from TypeScript using the SDK
|
|
31
|
-
- [8. Testing](testing.md) — Write automated tests for your feature
|
|
25
|
+
## What you'll build
|
|
32
26
|
|
|
27
|
+
* A `Brand` model with a rich text description and an uploadable logo — one generator command
|
|
28
|
+
* An admin UI for managing brands — one generator command, then customized
|
|
29
|
+
* A `brand` association on Products, surfaced in the product admin form
|
|
30
|
+
* Store API endpoints (`GET /api/v3/store/brands`) with serializers and prefixed IDs
|
|
31
|
+
* Typed TypeScript access to brands from your storefront via `@spree/sdk`
|
|
32
|
+
* Event subscribers and webhooks connecting the store to external systems
|
|
33
|
+
* Automated tests for all of it
|
|
34
|
+
|
|
35
|
+
## Tutorial Sections
|
|
33
36
|
|
|
34
|
-
## Example: Building a Brands Feature
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
- [1. Model](model.md) — Generate the Brand model — columns, rich text description, and logo upload in one command
|
|
39
|
+
- [2. Admin Dashboard](admin.md) — Scaffold the admin UI, then add the description editor, logo upload, and table columns
|
|
40
|
+
- [3. Extending Core Models](extending-models.md) — Connect Brands to Products using a decorator and an association
|
|
41
|
+
- [4. API](api.md) — Expose Brands through the Store and Admin APIs — generated in one command, or hand-built to learn the pieces
|
|
42
|
+
- [5. Events & Webhooks](events.md) — React to store activity and connect external systems — OMS, warehouse, ERP
|
|
43
|
+
- [6. SDK](sdk.md) — Consume Brand endpoints from TypeScript using the SDK
|
|
44
|
+
- [7. Testing](testing.md) — Write automated tests for your feature
|
|
@@ -1,41 +1,102 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Model
|
|
3
|
-
description:
|
|
3
|
+
description: Create the Brand model — columns, rich text description, and logo upload — with a single generator command
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
In this step we'll create the `Spree::Brand` model with everything it needs: a `name` column, a rich text `description`, and an uploadable `logo`.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## Step 1: Generate the Model
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
Spree ships a `spree:model` generator that produces a model and migration following all Spree conventions — `Spree::` namespacing, prefixed IDs, presence validations, and API filtering allowlists. It understands Rails attribute types including the virtual ones, so rich text and file attachments are part of the same command:
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
```bash Spree CLI (Docker)
|
|
14
|
+
spree generate model Brand name:string:index description:rich_text logo:attachment
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash Without Spree CLI
|
|
18
|
+
bin/rails g spree:model Brand name:string:index description:rich_text logo:attachment
|
|
12
19
|
```
|
|
13
20
|
|
|
14
|
-
This will create a couple of files:
|
|
15
|
-
- `app/models/spree/brand.rb` - the model file
|
|
16
|
-
- `db/migrate/XXXXXXXXXXXXXX_create_spree_brands.rb` - the database migration file
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
> **INFO:** Throughout this tutorial every command is shown in two forms. **Spree CLI** is for projects created with [create-spree-app](../create-spree-app/quickstart.md), where the app runs in Docker and `spree <command>` routes into the container. **Without Spree CLI** is for apps running Spree backend directly on your machine.
|
|
23
|
+
|
|
24
|
+
This creates two files:
|
|
25
|
+
|
|
26
|
+
- `app/models/spree/brand.rb` — the model
|
|
27
|
+
- `db/migrate/XXXXXXXXXXXXXX_create_spree_brands.rb` — the migration
|
|
28
|
+
|
|
29
|
+
Now apply the migration:
|
|
30
|
+
|
|
19
31
|
|
|
20
|
-
```bash
|
|
32
|
+
```bash Spree CLI (Docker)
|
|
33
|
+
spree migrate
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```bash Without Spree CLI
|
|
21
37
|
bin/rails db:migrate
|
|
22
38
|
```
|
|
23
39
|
|
|
24
|
-
This will create the table `spree_brands` with the column `name` in the database. The `name` column is indexed for faster lookups. Also the model file `app/models/spree/brand.rb` is created.
|
|
25
40
|
|
|
26
|
-
|
|
41
|
+
This creates the `spree_brands` table with an indexed `name` column. The `description` and `logo` attributes don't add columns — rich text lives in Action Text's `action_text_rich_texts` table, and uploads live in Active Storage's tables.
|
|
27
42
|
|
|
28
|
-
|
|
43
|
+
## Step 2: Understand the Generated Model
|
|
29
44
|
|
|
30
|
-
|
|
45
|
+
Open `app/models/spree/brand.rb`:
|
|
46
|
+
|
|
47
|
+
```ruby app/models/spree/brand.rb
|
|
31
48
|
module Spree
|
|
32
|
-
class Brand < Spree
|
|
33
|
-
|
|
49
|
+
class Brand < Spree.base_class
|
|
50
|
+
has_prefix_id :brand
|
|
51
|
+
|
|
52
|
+
has_rich_text :description
|
|
53
|
+
has_one_attached :logo
|
|
54
|
+
|
|
34
55
|
validates :name, presence: true
|
|
56
|
+
|
|
57
|
+
self.whitelisted_ransackable_attributes = %w[name]
|
|
58
|
+
self.whitelisted_ransackable_associations = %w[]
|
|
59
|
+
self.whitelisted_ransackable_scopes = %w[]
|
|
35
60
|
end
|
|
36
61
|
end
|
|
37
62
|
```
|
|
38
63
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
64
|
+
Line by line:
|
|
65
|
+
|
|
66
|
+
- **`Spree.base_class`** — inherits all Spree model functionality (multi-store scoping helpers, preferences, and more). The class is namespaced under `Spree::`, so it's available as `Spree::Brand`.
|
|
67
|
+
- **`has_prefix_id :brand`** — records get Stripe-style public IDs like `brand_k5nR8xLq`. APIs never expose raw database IDs.
|
|
68
|
+
- **`has_rich_text :description`** — formatted content via [Action Text](https://guides.rubyonrails.org/action_text_overview.html).
|
|
69
|
+
- **`has_one_attached :logo`** — file uploads via [Active Storage](https://guides.rubyonrails.org/active_storage_overview.html), with image processing and direct-to-storage uploads.
|
|
70
|
+
- **`validates :name, presence: true`** — generated automatically for required columns.
|
|
71
|
+
- **`whitelisted_ransackable_attributes`** — controls which attributes API clients may filter and sort by. Only allowlisted attributes are queryable, so adding `name` here is what later makes `?q[name_cont]=nike` work.
|
|
72
|
+
|
|
73
|
+
## Step 3: Try It in the Console
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
```bash Spree CLI (Docker)
|
|
77
|
+
spree console
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```bash Without Spree CLI
|
|
81
|
+
bin/rails console
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
brand = Spree::Brand.create!(name: "Wilson")
|
|
87
|
+
brand.prefixed_id # => "brand_k5nR8xLq"
|
|
88
|
+
|
|
89
|
+
brand.update!(description: "<h1>Hello</h1><p>World</p>")
|
|
90
|
+
brand.description.to_s # => rendered rich text HTML
|
|
91
|
+
brand.description.to_plain_text # => "Hello World"
|
|
92
|
+
|
|
93
|
+
Spree::Brand.find_by_prefix_id!("brand_k5nR8xLq") # lookup by public ID
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
We'll upload the logo through the admin UI in the next step — the model side is already done.
|
|
97
|
+
|
|
98
|
+
> **TIP:** The generator accepts more attribute types and options — references with auto-resolved class names (`user:belongs_to`), unique indexes (`slug:string:uniq`), soft delete (`--paranoid`), and custom fields support (`--metafields`). Run it with `--help` to see everything.
|
|
99
|
+
|
|
100
|
+
## Next Step
|
|
101
|
+
|
|
102
|
+
The model is complete. Now let's give admins a UI to manage brands: [Admin Dashboard](admin.md).
|
|
@@ -3,9 +3,9 @@ title: SDK
|
|
|
3
3
|
description: Use the TypeScript SDK to consume your custom Brand endpoints and extended Product data
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
In this tutorial, we'll use the `@spree/sdk` TypeScript SDK to consume the Brand API endpoints we created in the [
|
|
6
|
+
In this tutorial, we'll use the `@spree/sdk` TypeScript SDK to consume the Brand API endpoints we created in the [API tutorial](api.md), and work with the extended Product data that now includes brand information.
|
|
7
7
|
|
|
8
|
-
> **INFO:** This guide assumes you've completed the [
|
|
8
|
+
> **INFO:** This guide assumes you've completed the [API](api.md) tutorial and have the Brand endpoints running.
|
|
9
9
|
|
|
10
10
|
## What We're Building
|
|
11
11
|
|
|
@@ -115,7 +115,7 @@ const full = await client.products.get(
|
|
|
115
115
|
|
|
116
116
|
### Filtering Products by Brand
|
|
117
117
|
|
|
118
|
-
Ransack predicates work on whitelisted attributes and associations. The [
|
|
118
|
+
Ransack predicates work on whitelisted attributes and associations. The [API tutorial](api.md) shows how to register `brand_id` and `brand` via `Spree.ransack` — once that's done, you can filter:
|
|
119
119
|
|
|
120
120
|
```typescript
|
|
121
121
|
// Products from a specific brand
|
|
@@ -164,6 +164,7 @@ products.data.forEach(p => {
|
|
|
164
164
|
|
|
165
165
|
## Related Documentation
|
|
166
166
|
|
|
167
|
-
- [
|
|
167
|
+
- [API Tutorial](api.md) - Creating the Brand API endpoints
|
|
168
168
|
- [SDK Overview](/sdk) - Full SDK documentation
|
|
169
169
|
- [Search & Filtering](../core-concepts/search-filtering.md) - Ransack predicates and sorting
|
|
170
|
+
- [Agentic Development](../agentic/overview.md) - Agent skills and the docs MCP server cover the SDK patterns used here
|
|
@@ -7,30 +7,35 @@ Automated testing is a crucial part of the development process. It helps you ens
|
|
|
7
7
|
Spree uses [RSpec](https://rspec.info), [Factory Bot](https://github.com/thoughtbot/factory_bot_rails), and [Capybara](https://github.com/teamcapybara/capybara) for testing.
|
|
8
8
|
We also provide the `spree_dev_tools` gem that helps you write Spree-specific tests.
|
|
9
9
|
|
|
10
|
-
> **INFO:** This guide assumes you've completed all previous tutorials through [
|
|
10
|
+
> **INFO:** This guide assumes you've completed all previous tutorials through [API](api.md). You should have a complete `Spree::Brand` model with admin features and API endpoints.
|
|
11
11
|
|
|
12
12
|
## Setup
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
**If your app came from [create-spree-app](../create-spree-app/quickstart.md) or [spree-starter](https://github.com/spree/spree-starter), the test environment is already set up** — RSpec, Factory Bot, Capybara, DatabaseCleaner, and the `spree_dev_tools` helpers (`stub_authorization!`, the `'API v3 Store'` shared context, Spree factories) ship preconfigured in `spec/support/`. Skip to creating the fixtures file below.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
```
|
|
16
|
+
<details>
|
|
17
|
+
<summary>Setting up an app that doesn't have RSpec yet</summary>
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
For an existing Rails app without test setup, install RSpec and the Spree test helpers:
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
```bash Spree CLI (Docker)
|
|
23
|
+
spree generate rspec:install
|
|
24
|
+
spree generate spree_dev_tools:install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```bash Without Spree CLI
|
|
28
|
+
bin/rails g rspec:install
|
|
23
29
|
bin/rails g spree_dev_tools:install
|
|
24
30
|
```
|
|
25
31
|
|
|
26
|
-
This adds Spree-specific test helpers to your `spec/support/` directory, including:
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
* and more…
|
|
33
|
+
The `spree_dev_tools` generator adds the Spree-specific helpers to `spec/support/`: authorization helpers (`stub_authorization!`), Factory Bot configuration, Capybara setup for feature tests, and more.
|
|
34
|
+
|
|
35
|
+
</details>
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
|
|
38
|
+
### Create the Fixtures Directory and File
|
|
34
39
|
|
|
35
40
|
When writing tests that involve file attachments (like images, PDFs, etc.), you need fixture files that your factories can use. Here's how to set them up.
|
|
36
41
|
|
|
@@ -38,13 +43,11 @@ When writing tests that involve file attachments (like images, PDFs, etc.), you
|
|
|
38
43
|
mkdir -p spec/fixtures/files && printf '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\x0f\x00\x00\x01\x01\x00\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82' > spec/fixtures/files/logo.png
|
|
39
44
|
```
|
|
40
45
|
|
|
41
|
-
###
|
|
46
|
+
### What the generators already created
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
bin/rails g rspec:model Spree::Brand
|
|
45
|
-
```
|
|
48
|
+
If you used `spree generate api_resource` in the [API step](api.md), you already have controller specs (`spec/controllers/spree/api/v3/store/brands_controller_spec.rb` and `…/admin/brands_controller_spec.rb`) and a factory (`spec/factories/spree/brand_factory.rb`). The sections below build the same things by hand — compare as you go, and keep whichever you prefer.
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
For the model spec, create `spec/models/spree/brand_spec.rb` — we'll fill it in below.
|
|
48
51
|
|
|
49
52
|
## Writing Factories
|
|
50
53
|
|
|
@@ -213,10 +216,11 @@ Controller tests verify that your endpoints respond correctly and perform the ex
|
|
|
213
216
|
|
|
214
217
|
### Store API Controller Tests
|
|
215
218
|
|
|
216
|
-
Test the API endpoints we created in the [
|
|
219
|
+
Test the API endpoints we created in the [API tutorial](api.md). Store API tests use the `'API v3 Store'` shared context which sets up a store, publishable API key, and JWT tokens — it ships in the `spree_api` gem, so require `spree/api/testing_support/v3/base` at the top of the spec.
|
|
217
220
|
|
|
218
221
|
```ruby spec/controllers/spree/api/v3/store/brands_controller_spec.rb
|
|
219
222
|
require 'rails_helper'
|
|
223
|
+
require 'spree/api/testing_support/v3/base'
|
|
220
224
|
|
|
221
225
|
RSpec.describe Spree::Api::V3::Store::BrandsController, type: :controller do
|
|
222
226
|
render_views
|
|
@@ -320,6 +324,7 @@ Test that the custom Product serializer includes brand data:
|
|
|
320
324
|
|
|
321
325
|
```ruby spec/controllers/spree/api/v3/store/products_brand_spec.rb
|
|
322
326
|
require 'rails_helper'
|
|
327
|
+
require 'spree/api/testing_support/v3/base'
|
|
323
328
|
|
|
324
329
|
RSpec.describe Spree::Api::V3::Store::ProductsController, type: :controller do
|
|
325
330
|
render_views
|
|
@@ -582,23 +587,35 @@ expect(page).to have_content('Success!')
|
|
|
582
587
|
|
|
583
588
|
## Running Tests
|
|
584
589
|
|
|
585
|
-
|
|
586
|
-
# Run all tests
|
|
587
|
-
bundle exec rspec
|
|
590
|
+
In the Docker flow the container's `DATABASE_URL` points at the development database, so tests need two overrides: a dedicated test database, and DatabaseCleaner's opt-in for non-localhost database hosts (its safeguard against cleaning a database it doesn't own). One-time test database setup:
|
|
588
591
|
|
|
589
|
-
|
|
590
|
-
|
|
592
|
+
```bash Spree CLI (Docker) — one-time setup
|
|
593
|
+
spree exec env RAILS_ENV=test DATABASE_URL=postgres://postgres@postgres:5432/spree_test bin/rails db:prepare
|
|
594
|
+
```
|
|
591
595
|
|
|
592
|
-
|
|
593
|
-
bundle exec rspec spec/models/spree/brand_spec.rb:15
|
|
596
|
+
Then run tests:
|
|
594
597
|
|
|
595
|
-
# Run with documentation format
|
|
596
|
-
bundle exec rspec --format documentation
|
|
597
598
|
|
|
598
|
-
|
|
599
|
-
|
|
599
|
+
```bash Spree CLI (Docker)
|
|
600
|
+
# Define once per shell (or add as an alias):
|
|
601
|
+
alias spree-rspec='spree exec env RAILS_ENV=test DATABASE_URL=postgres://postgres@postgres:5432/spree_test DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL=true bundle exec rspec'
|
|
602
|
+
|
|
603
|
+
spree-rspec # all tests
|
|
604
|
+
spree-rspec spec/models/spree/brand_spec.rb # specific file
|
|
605
|
+
spree-rspec spec/models/spree/brand_spec.rb:15 # specific test
|
|
606
|
+
spree-rspec --format documentation # documentation format
|
|
607
|
+
spree-rspec spec/features/ # only feature tests
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
```bash Without Spree CLI
|
|
611
|
+
bundle exec rspec # all tests
|
|
612
|
+
bundle exec rspec spec/models/spree/brand_spec.rb # specific file
|
|
613
|
+
bundle exec rspec spec/models/spree/brand_spec.rb:15 # specific test
|
|
614
|
+
bundle exec rspec --format documentation # documentation format
|
|
615
|
+
bundle exec rspec spec/features/ # only feature tests
|
|
600
616
|
```
|
|
601
617
|
|
|
618
|
+
|
|
602
619
|
## Best Practices
|
|
603
620
|
|
|
604
621
|
|
|
@@ -659,7 +676,7 @@ spec/
|
|
|
659
676
|
* [Model Tutorial](model.md) - Creating the Brand model
|
|
660
677
|
* [Admin Tutorial](admin.md) - Building the admin interface
|
|
661
678
|
* [Extending Core Models](extending-models.md) - Connecting Brands to Products
|
|
662
|
-
* [
|
|
679
|
+
* [API Tutorial](api.md) - Creating Brand API endpoints
|
|
663
680
|
* [RSpec Documentation](https://rspec.info/documentation/) - Official RSpec docs
|
|
664
681
|
* [Factory Bot Documentation](https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md) - Factory Bot guide
|
|
665
682
|
|
package/package.json
CHANGED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: File Uploads
|
|
3
|
-
description: Learn how to add file uploads to the Brands feature
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
> **INFO:** This guide assumes you've completed the [Model](model.md), [Admin](admin.md), and [Rich Text](rich-text.md) tutorials.
|
|
7
|
-
|
|
8
|
-
In this tutorial, we'll add a logo image upload to our Brand model. Spree uses [Rails Active Storage](https://guides.rubyonrails.org/active_storage_overview.html) for handling file attachments, image processing, and storage.
|
|
9
|
-
|
|
10
|
-
## Step 1: Add Attachment to the Model
|
|
11
|
-
|
|
12
|
-
First, let's add a logo attachment to the Brand model:
|
|
13
|
-
|
|
14
|
-
```ruby app/models/spree/brand.rb {3}
|
|
15
|
-
module Spree
|
|
16
|
-
class Brand < Spree::Base
|
|
17
|
-
has_one_attached :logo
|
|
18
|
-
|
|
19
|
-
# ... existing code ...
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Step 2: Permit the Attachment Attribute
|
|
25
|
-
|
|
26
|
-
For the admin form to accept the file upload, we need to permit the `logo` attribute in the controller.
|
|
27
|
-
|
|
28
|
-
Update your brands controller:
|
|
29
|
-
|
|
30
|
-
```ruby app/controllers/spree/admin/brands_controller.rb {10}
|
|
31
|
-
module Spree
|
|
32
|
-
module Admin
|
|
33
|
-
class BrandsController < ResourceController
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
def permitted_resource_params
|
|
37
|
-
params.require(:brand).permit(
|
|
38
|
-
:name,
|
|
39
|
-
:description,
|
|
40
|
-
:logo
|
|
41
|
-
)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Step 3: Add File Upload Field to the Admin Form
|
|
49
|
-
|
|
50
|
-
Now let's add the file upload field to the brand form. Spree provides a `spree_file_field` helper that handles everything including:
|
|
51
|
-
|
|
52
|
-
- Drag and drop upload
|
|
53
|
-
- Image preview
|
|
54
|
-
- Direct upload to storage
|
|
55
|
-
- Optional image cropping
|
|
56
|
-
|
|
57
|
-
Update your brand form partial:
|
|
58
|
-
|
|
59
|
-
```erb app/views/spree/admin/brands/_form.html.erb {11-19}
|
|
60
|
-
<div class="card mb-6">
|
|
61
|
-
<div class="card-header">
|
|
62
|
-
<h5 class="card-title"><%= Spree.t(:general_settings) %></h5>
|
|
63
|
-
</div>
|
|
64
|
-
<div class="card-body">
|
|
65
|
-
<%= f.spree_text_field :name, required: true %>
|
|
66
|
-
<%= f.spree_rich_text_area :description %>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
|
|
70
|
-
<div class="card mb-6">
|
|
71
|
-
<div class="card-header">
|
|
72
|
-
<h5 class="card-title"><%= Spree.t(:logo) %></h5>
|
|
73
|
-
</div>
|
|
74
|
-
<div class="card-body">
|
|
75
|
-
<%= f.spree_file_field :logo, width: 300, height: 300 %>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Add cropping functionality
|
|
81
|
-
|
|
82
|
-
To enable cropping functionality, add the `crop: true` option to the `spree_file_field` helper.
|
|
83
|
-
|
|
84
|
-
## Step 4: Display the Logo in the Index Table
|
|
85
|
-
|
|
86
|
-
Let's show a thumbnail of the brand logo in the admin index view.
|
|
87
|
-
|
|
88
|
-
Update the table header partial:
|
|
89
|
-
|
|
90
|
-
```erb app/views/spree/admin/brands/_table_header.html.erb {2}
|
|
91
|
-
<tr>
|
|
92
|
-
<th><%= Spree.t(:logo) %></th>
|
|
93
|
-
<th><%= Spree.t(:name) %></th>
|
|
94
|
-
<th></th>
|
|
95
|
-
</tr>
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Update the table row partial to display the logo:
|
|
99
|
-
|
|
100
|
-
```erb app/views/spree/admin/brands/_table_row.html.erb {3-12}
|
|
101
|
-
<tr id="<%= spree_dom_id brand %>" class="cursor-pointer" data-controller="row-link">
|
|
102
|
-
<td data-action="click->row-link#openLink" class="w-70">
|
|
103
|
-
<div class="d-flex align-items-center gap-2">
|
|
104
|
-
<% if brand.logo.attached? %>
|
|
105
|
-
<%= spree_image_tag brand.logo, width: 48, height: 48, class: 'rounded' %>
|
|
106
|
-
<% else %>
|
|
107
|
-
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;">
|
|
108
|
-
<%= icon('photo-off', class: 'text-muted') %>
|
|
109
|
-
</div>
|
|
110
|
-
<% end %>
|
|
111
|
-
<span class="font-weight-bold"><%= brand.name %></span>
|
|
112
|
-
</div>
|
|
113
|
-
</td>
|
|
114
|
-
<td data-action="click->row-link#openLink" class="w-20">
|
|
115
|
-
<%= spree_date(brand.created_at) %>
|
|
116
|
-
</td>
|
|
117
|
-
<td class="actions w-10">
|
|
118
|
-
<%= link_to_edit(brand, data: { row_link_target: :link, turbo_frame: '_top' }) if can? :edit, brand %>
|
|
119
|
-
</td>
|
|
120
|
-
</tr>
|
|
121
|
-
```
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Rich Text
|
|
3
|
-
description: Learn how to add rich text content to the Brands feature using Action Text
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
> **INFO:** This guide assumes you've completed the [Model](model.md) and [Admin](admin.md) tutorials.
|
|
7
|
-
|
|
8
|
-
Our Brand model has a `name` attribute to store the brand name. However it's missing a description. That's because we're going to use [Action Text](https://guides.rubyonrails.org/action_text_overview.html) to handle the rich text content.
|
|
9
|
-
|
|
10
|
-
## Step 1: Add Action Text to the Model
|
|
11
|
-
|
|
12
|
-
```ruby app/models/spree/brand.rb {4-5}
|
|
13
|
-
module Spree
|
|
14
|
-
class Brand < Spree::Base
|
|
15
|
-
# Action text for rich text content
|
|
16
|
-
has_rich_text :description
|
|
17
|
-
|
|
18
|
-
# ... other code ...
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
You don't need to run any migrations, as we won't be adding any new columns to the `spree_brands` table. That's because [Action Text](https://guides.rubyonrails.org/action_text_overview.html) stores all the rich text content in a separate table called `action_text_rich_texts`.
|
|
24
|
-
|
|
25
|
-
You can access the description content in code like this:
|
|
26
|
-
|
|
27
|
-
```ruby
|
|
28
|
-
brand.description.to_s
|
|
29
|
-
# => "<h1>Hello</h1><p>World</p>"
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Or if you prefer plain text:
|
|
33
|
-
|
|
34
|
-
```ruby
|
|
35
|
-
brand.description.to_plain_text
|
|
36
|
-
# => "Hello World"
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Step 2: Add a WYSIWYG editor to the Admin Dashboard
|
|
40
|
-
|
|
41
|
-
In the Admin dashboard we want to use a WYSIWYG editor to add formatted text to the brand description. To do this, edit the `app/views/spree/admin/brands/_form.html.erb` file and add the following code:
|
|
42
|
-
|
|
43
|
-
```erb app/views/spree/admin/brands/_form.html.erb {4}
|
|
44
|
-
<div class="card mb-6">
|
|
45
|
-
<div class="card-body">
|
|
46
|
-
<%= f.spree_text_field :name %>
|
|
47
|
-
<%= f.spree_rich_text_area :description %>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
This will render a WYSIWYG editor to the brand description field in the Admin dashboard.
|
|
53
|
-
|
|
54
|
-
## Step 3: Update permitted parameters in controller
|
|
55
|
-
|
|
56
|
-
To permit the `description` attribute to be saved, we need to update the permitted parameters in the controller file and add the following code:
|
|
57
|
-
|
|
58
|
-
```ruby app/controllers/spree/admin/brands_controller.rb {9}
|
|
59
|
-
module Spree
|
|
60
|
-
module Admin
|
|
61
|
-
class BrandsController < ResourceController
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
def permitted_resource_params
|
|
65
|
-
params.require(:brand).permit(
|
|
66
|
-
:name,
|
|
67
|
-
:description
|
|
68
|
-
)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
```
|