spree-resource について
spree-resource は、CLI で API リソースを生成する Spree 開発者向けガイドです。モデル、マイグレーション、Store と Admin API の構成に加え、フィールド規約、権限、ルート、生成ファイルの管理方法を説明します。
主な機能
- 01モデルとデータベースマイグレーションの生成
- 02Store・Admin API のコントローラーとシリアライザー生成
- 03ルートと権限スコープの設定
- 04ストアスコープ、ライフサイクルイベント、カスタムフィールドの指定
- 05生成ファイルの管理規約の説明
活用シーン
- 01Spree に新しい API リソースを追加
- 02読み取り専用カタログや書き込み可能な顧客リソースを作成
- 03管理画面専用リソースを生成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ spree/ agent-skills --skill spree-resourceインストール後、Claude Code で/spree-resourceを入力して読み込まれたか確認します。
詳細
Spree リソースの追加
コマンドは Spree CLI(
spree …、Docker、server/内の Rails アプリ)を使用します。CLI を使わない従来の Rails アプリでは、アプリのルートディレクトリからbin/rails g spree:api_resource …を実行し、パスからserver/のプレフィックスを外してください(spree-projectを参照)。
v3 API で公開するモデルを追加するには、spree:api_resource ジェネレーターを使用します。1 つのコマンドで、次のものが生成されます。
- モデル(
server/app/models/spree/<name>.rb)とそのマイグレーション - Store API と Admin API のコントローラーおよびシリアライザー
- FactoryBot ファクトリーと、両方の API 用コントローラースペック
- アプリの
config/routes.rbにあるSpree::Core::Engine.add_routesブロック内のルート定義 read_<plural>/write_<plural>権限スコープ(config/initializers/spree.rbに追加されるSpree.permissions.register_scope)と、そのロールエディターのラベル(config/locales/spree_<plural>.en.yml)— Admin のみ
前提条件:先に spree eject を実行してください。ジェネレーターは Web コンテナ内で実行されます。また、./server をバインドマウントするのは eject 済みの開発用 compose のみなので、生成されたファイルはホスト上に表示され、保持されます。
1 つのコマンドで実行する方法
spree 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)
フィールドの構文は Rails の属性パーサーに従い、Spree の規約が適用されます。
| 入力内容 | 生成されるもの |
|---|---|
name:string / :text / :integer / :decimal / :boolean / :date / :datetime | null: false のカラム。boolean 以外のフィールドには presence バリデーション |
name:string:index | 非ユニークインデックス |
slug:string:uniq | ユニークインデックスと一意性バリデーション。モデルがストアスコープの場合(デフォルト)、store_id でスコープされ、さらに spree_base_uniqueness_scope が適用されます |
brand:belongs_to(または :references) | class_name とインデックスを持つ belongs_to。外部キー制約なし、null: false |
category:belongs_to{TaxCategory} | 明示的なクラスヒント(非修飾名のみ)→ class_name: 'TaxCategory'。Spree 名前空間内で解決されます |
description:rich_text | has_spree_rich_text と Spree::SanitizableRichText |
logo:attachment / photos:attachments | has_one_attached / has_many_attached |
belongs_to のクラス解決:user → Spree.customer_class、admin_user、created_by、approver、canceler → Spree.admin_user_class、それ以外 → Spree::<Camelized>。
フラグ
| フラグ | デフォルト | 効果 |
|---|---|---|
--writable | オフ | Store API で create/update/destroy が可能になります。デフォルトの Store API は読み取り専用(index + show)です。 |
--no-store | — | Store API のコントローラー、シリアライザー、ルートをスキップします。Admin 専用のリソースです。 |
--no-admin | — | Admin API の機能をスキップします。まれなケースです。 |
--store-name=Discount | — | Store API で別の名前(/api/v3/store/discounts)として公開します。モデル、テーブル、Admin API では標準名が維持されます。 |
--no-store-scoped | スコープあり | デフォルトでは、モデルに Spree::SingleStoreResource(store_id カラム、belongs_to :store、Spree::Current.store からの自動割り当て、for_store スコープ、後からのストア変更不可)が含まれます。グローバルな参照データの場合にのみ無効にしてください。 |
--no-lifecycle-events | オン | デフォルトでは、モデルが publishes_lifecycle_events を呼び出します(サブスクライバーと Webhook 向けの brand.created/updated/deleted イベント)。 |
--custom-fields | オフ | Spree::HasCustomFields と Spree::Metadata(マーチャント定義のカスタムフィールドと metadata JSON)を含めます。 |
--paranoid | オフ | acts_as_paranoid と deleted_at カラム/インデックスを追加します。Admin シリアライザーで deleted_at を公開します。 |
--id-prefix=br | スネークケースにしたクラス名 | プレフィックス付き ID のプレフィックス(デフォルトは brand_…)。Core では短いプレフィックスを使用します:prod_、variant_、cart_、or_、py_、ful_、cust_、sl_。 |
--parent=Spree::Foo | Spree.base_class | 親クラスの式。 |
--permission-group=settings | catalog | ロールエディターと API キーのスコープ選択画面で read_ / write_ キーが表示される場所(orders、catalog、customers、settings など、または独自の小文字の識別子)。 |
--skip-routes | オフ | ルートを変更しません。 |
--skip-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
end
ルート。 ジェネレーターは、config/routes.rb の Spree::Core::Engine.add_routes 内にある namespace :store / namespace :admin ブロックに、それぞれ resources :brands, only: [:index, :show](ストア)と resources :brands(管理者)を挿入します(create-spree-app / spree-starter では、このブロックは空の状態で提供されます)。ブロックまたは名前空間がない場合は、警告を出してスキップします。手動で追加してください:
Rails.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: '/'
end
「一度だけ所有/管理対象/追記のみ」の契約
- モデル(一度だけ所有) — 一度だけ書き込まれ、再実行しても変更されません。バリデーション、スコープ、アソシエーションはここに記述します。
- マイグレーション(追記のみ) — 一度だけ生成されます。スキーマの変更には、新しいマイグレーションを使用します:
spree generate migration AddLogoToSpreeBrands logo_url:string。 - コントローラー、シリアライザー、ファクトリー、スペック(管理対象) — 再実行時に上書きされます。手動で編集した場合、そのリソースに対してジェネレーターを再実行しないでください(または、編集内容を再適用してください)。
- ルートと権限スコープ(冪等) — ルートの行または
register_scope(:brands, …)がすでに存在する場合、重複して追加されません。権限のロケールファイルは一度だけ所有されるため、編集したラベルは再実行後も保持されます。
ジェネレーターの実行後
-
モデルを確認する — バリデーション、アソシエーション、スコープを追加します。生成される
belongs_toは必須です(Spree のモデルでは、デフォルトでbelongs_toが必須です。失敗時のメッセージは「must exist」です)。任意の参照にするにはoptional: trueを追加し、マイグレーションのnull: falseを緩和します。 -
マイグレーションを実行する —
spree migrate。 -
権限を付与する — Admin コントローラーは
scoped_resource :brandsを宣言し、ジェネレーターはconfig/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] })スタッフのロール(ダッシュボードの Settings → Roles、Admin API、またはシード)に
read_brands/write_brandsを付与するか、シークレットキーにそれらを設定するまでは、フルアクセスのプリンシパルのみがアクセスできます(adminロール、read_all/write_allキー)。ラベルはspree.permissions_catalog.resources.brands(label、任意のdescription)にあります。--no-adminを指定すると、何も登録されません。spree-auth-permissionsを参照してください。 -
読み取り時のストアスコープ — ベースコントローラーは、コレクションを
Model.for_store(current_store)でスコープします。SingleStoreResourceがこのスコープを提供します。--no-store-scopedモデルでは、アソシエーションがあればfor_storeはcurrent_store.<plural>にフォールバックし、なければテーブル全体にフォールバックします。current_store.brandsを使いたい場合は、デコレーター経由でSpree::Storeにhas_many :brands, class_name: 'Spree::Brand', dependent: :destroyを追加します。権限によって決まるのは、ブランドを読み取れるかどうかであり、どのブランドを読み取れるかではありません。検索はストアスコープのままにしてください。 -
許可する属性 — 生成されるコントローラーでは、
permitted_paramsのオーバーライドではなく、resource_permitted_attributesで書き込み可能なカラムを宣言します。そのため、拡張機能が宣言した属性(Spree::Brand.additional_permitted_attributes += [...])とパラメーターの正規化は引き続き適用されます:def resource_permitted_attributes [:name, :slug, :active] endクライアントが書き込むべきでないカラムを除外するには、このリストを編集します。ただし、コントローラーは管理対象のため、再実行するとテンプレートに戻ります。
-
スペックを実行する —
spree rspec spec/controllers/spree/api/v3/。スペックでは、spree_apiのテストサポートが提供する'API v3 Store guest'/'API v3 Admin authenticated'の共有コンテキストを使用します(spree-testingを参照してください)。
ステータスの追加
Spree にステートマシンはありません。ライフサイクルを持つレコードには、文字列の status カラムを追加して Spree::HasStatus を使用します。遷移はワークフローに記述します(spree-workflows を参照してください):
include Spree::HasStatus
has_status :draft, :active, :archived, default: :draft # predicates (active?), scopes (.active), inclusion validation, .with_status(...)
拡張機能では、Spree::Brand.add_status('paused', after: 'active') を使ってステータスを追加できます。ステータスには Rails の enum を使用しないでください。
TypeScript の型
プロジェクト内で生成するシリアライザーはアプリ内のものであり、公開されている @spree/sdk / @spree/admin-sdk の型には含まれません。独自のエンドポイントは、手書きの型とともに client.request<T>(...) で呼び出します(spree-typescript-sdk を参照してください)。生成されるシリアライザーの typelize 行には、JSON の型が記載されています(小数は文字列としてシリアライズされます)。
一般的なパターン
# 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-scoped
書き込み可能な顧客リソースでは、Store API は所有権に基づいて認可されることを忘れないでください。Store コントローラーの scope をオーバーライドし、顧客経由で読み取るようにします(例:current_user.saved_lists)。そうしないと、すべての購入者がストア内のすべてのレコードを閲覧できてしまいます。
モデルのみ — API サーフェスなし
spree:model は、同じ規約(ID のプレフィックス、Spree.base_class、ストアスコープ、ライフサイクルイベント、null: false、外部キーなし、Ransack の許可リスト)に従ってモデルとマイグレーションを生成し、同じモデルフラグ(--paranoid、--custom-fields、--id-prefix、--parent、--no-store-scoped、--no-lifecycle-events)を受け付けます。api_resource と異なり、Rails のテストフレームワーク用フックはそのまま維持されるため、rspec/factory_bot が設定されていれば、スタブのモデルスペックとファクトリーも生成されます。
spree generate model BrandImage position:integer brand:belongs_to
レコードが内部用(ログ、結合テーブル)の場合、親の API 経由でのみアクセスする場合、またはコントローラーを手書きする場合に使用してください。後から API を追加するには、spree generate api_resource Brand … を実行します。既存のモデルを検出してモデルとマイグレーションをスキップし(所有者による一度限りの生成)、API サーフェスのみを生成します。
注意点
- 外部キー制約や Rails の enum は追加しないでください。
foreign_key: falseと文字列のステータスを使用してください。 - コアモデルの拡張(例:products の
brand_id)は、デコレーターとSpree::Product.additional_permitted_attributes += [:brand_id]で行います(配列は凍結されているため、<<は使用しないでください)。spree-decoratorsを参照してください。 - ジョブ、rake タスク、コンソール: ストアスコープのレコードにはストアが必要です。
Spree::Current.store = storeを設定してください(Spree::Store.defaultは nil の場合があるため、これに依存しないでください)。 - カスタムの読み取り専用メンバーアクション — コントローラーの
read_actionsに追加し、write_*ではなくread_*にマッピングされるようにしてください。
さらに詳しく読むには
node_modules/@spree/docs/dist/developer/tutorial/model-and-api.md— Brand の一連の手順を最初から最後まで解説node_modules/@spree/docs/dist/developer/customization/permissions.md—register_scopenode_modules/@spree/docs/dist/developer/customization/api.md— API の拡張- ジェネレーターのソース:
spree/core/lib/generators/spree/{api_resource,model}/