Loading...
Loading...
Use when the user wants to add a new model, database table, or REST API endpoint to a Spree 6 project. Covers `spree:api_resource` (model + migration + Store/Admin API controllers + serializers + factory + controller specs + routes + permission scope) and `spree:model` (model + migration only). Common phrasings include "add a Brand model", "create a new resource", "expose X as an API endpoint", "add an Admin API for Y", "scaffold a Spree resource", "create a Spree model without an API", "internal model", "make my model store-scoped".
npx skill4agent add spree/agent-skills spree-resourceCommands use the Spree CLI (, Docker, Rails app inspree …). On a classic Rails app without the CLI, runserver/from the app root and drop thebin/rails g spree:api_resource …prefix from paths (seeserver/).spree-project
spree:api_resourceserver/app/models/spree/<name>.rbSpree::Core::Engine.add_routesconfig/routes.rbread_<plural>write_<plural>Spree.permissions.register_scopeconfig/initializers/spree.rbconfig/locales/spree_<plural>.en.ymlspree eject./serverspree generate api_resource Brand name:string:index slug:string:uniq active:boolean
spree migrate✓ Generated Spree::Brand API resource
Prefixed ID: brand_xxxxxxxxxx
Store API: /api/v3/store/brands (read-only)
Admin API: /api/v3/admin/brands (full CRUD)| You write | You get |
|---|---|
| |
| Non-unique index |
| Unique index + uniqueness validation — scoped to |
| |
| Explicit class hint (unqualified names only) → |
| |
| |
belongs_touserSpree.customer_classadmin_usercreated_byapprovercancelerSpree.admin_user_classSpree::<Camelized>| Flag | Default | Effect |
|---|---|---|
| off | Store API gets create/update/destroy. Default Store API is read-only (index + show). |
| — | Skip the Store API controller + serializer + route. Admin-only resource. |
| — | Skip the Admin API surface. Rare. |
| — | Expose the Store API under a different name ( |
| scoped | By default the model includes |
| on | By default the model calls |
| off | Includes |
| off | |
| snake-cased class name | Prefixed-ID prefix ( |
| | Parent class expression. |
| | Where the |
| off | Don't touch routes. |
| off | Don't generate controller specs. |
server/app/models/spree/brand.rb (owned-once)
server/db/migrate/<ts>_create_spree_brands.rb (append-only)
server/app/controllers/spree/api/v3/store/brands_controller.rb (managed)
server/app/controllers/spree/api/v3/admin/brands_controller.rb (managed)
server/app/serializers/spree/api/v3/brand_serializer.rb (managed)
server/app/serializers/spree/api/v3/admin/brand_serializer.rb (managed)
server/spec/factories/spree/brand_factory.rb (managed)
server/spec/controllers/spree/api/v3/{store,admin}/brands_controller_spec.rb (managed)
server/config/routes.rb (idempotent inject)
server/config/initializers/spree.rb (idempotent append — register_scope)
server/config/locales/spree_brands.en.yml (owned-once — permission label)module Spree
class Brand < Spree.base_class
include Spree::SingleStoreResource
has_prefix_id :brand
publishes_lifecycle_events
validates :name, presence: true
validates :slug, presence: true, uniqueness: { scope: [:store_id, *spree_base_uniqueness_scope] }
self.whitelisted_ransackable_attributes = %w[name slug active]
self.whitelisted_ransackable_associations = %w[]
self.whitelisted_ransackable_scopes = %w[]
end
endresources :brands, only: [:index, :show]resources :brandsnamespace :storenamespace :adminSpree::Core::Engine.add_routesconfig/routes.rbRails.application.routes.draw do
Spree::Core::Engine.add_routes do
namespace :api, defaults: { format: 'json' } do
namespace :v3 do
namespace :store do
resources :brands, only: [:index, :show]
end
namespace :admin do
resources :brands
end
end
end
end
mount Spree::Core::Engine, at: '/'
endspree generate migration AddLogoToSpreeBrands logo_url:stringregister_scope(:brands, …)belongs_tobelongs_tooptional: truenull: falsespree migratescoped_resource :brandsconfig/initializers/spree.rb# Permissions for the Brand API — grants read_brands / write_brands
# to staff roles and secret API keys. Labels: config/locales/spree_brands.en.yml
Spree.permissions.register_scope(:brands, group: :catalog, resources: -> { [Spree::Brand] })read_brandswrite_brandsadminread_allwrite_allspree.permissions_catalog.resources.brandslabeldescription--no-adminspree-auth-permissionsModel.for_store(current_store)SingleStoreResource--no-store-scopedfor_storecurrent_store.<plural>has_many :brands, class_name: 'Spree::Brand', dependent: :destroySpree::Storecurrent_store.brandsresource_permitted_attributespermitted_paramsSpree::Brand.additional_permitted_attributes += [...]def resource_permitted_attributes
[:name, :slug, :active]
endspree rspec spec/controllers/spree/api/v3/'API v3 Store guest''API v3 Admin authenticated'spree_apispree-testingstatusSpree::HasStatusspree-workflowsinclude Spree::HasStatus
has_status :draft, :active, :archived, default: :draft # predicates (active?), scopes (.active), inclusion validation, .with_status(...)Spree::Brand.add_status('paused', after: 'active')@spree/sdk@spree/admin-sdkclient.request<T>(...)spree-typescript-sdktypelize# Read-only catalog resource (Store GET, Admin CRUD)
spree generate api_resource Brand name:string:uniq active:boolean
# Writable customer-facing resource
spree generate api_resource SavedList label:string user:belongs_to --writable
# Admin-only back-office data
spree generate api_resource SupplierNote body:text --no-store
# Soft-delete + custom fields
spree generate api_resource Vendor name:string:uniq slug:string:uniq --paranoid --custom-fields
# Global reference data (no store_id)
spree generate api_resource Certification code:string:uniq --no-store-scopedscopecurrent_user.saved_listsspree:modelSpree.base_classnull: false--paranoid--custom-fields--id-prefix--parent--no-store-scoped--no-lifecycle-eventsapi_resourcespree generate model BrandImage position:integer brand:belongs_tospree generate api_resource Brand …foreign_key: falsebrand_idSpree::Product.additional_permitted_attributes += [:brand_id]<<spree-decoratorsSpree::Current.store = storeSpree::Store.defaultread_actionsread_*write_*node_modules/@spree/docs/dist/developer/tutorial/model-and-api.mdnode_modules/@spree/docs/dist/developer/customization/permissions.mdregister_scopenode_modules/@spree/docs/dist/developer/customization/api.mdspree/core/lib/generators/spree/{api_resource,model}/