spree-extensions について
Spree 6の拡張機能を開発するためのスキルです。Rails engine gemを基本とし、任意でダッシュボードプラグインを追加できます。構成、APIリソース、登録、プロバイダー、テスト、連携時の注意点を扱います。
主な機能
- 01Rails engine構成の拡張gemを作成
- 02StoreおよびAdmin APIリソースを追加
- 03フック、プロバイダー、サブスクライバーを登録
- 04任意のダッシュボードプラグインを作成
- 05RSpecとFactory Botで拡張をテスト
活用シーン
- 01複数のSpreeアプリで共有するカスタマイズのパッケージ化
- 02ストア単位のリソースとAPIエンドポイントの追加
- 03決済またはフルフィルメントプロバイダーの連携
- 04ダッシュボードプラグインによるAdmin画面の追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ spree/ agent-skills --skill spree-extensionsインストール後、Claude Code で/spree-extensionsを入力して読み込まれたか確認します。
詳細
Spree 拡張機能
コマンドでは
spreeCLI 形式を使用します(Rails アプリはserver/にあります)。従来型の Rails アプリでは、アプリのルートからbundle …/bin/rails …を実行してください。詳しくはspree-projectを参照してください。
Spree 6 の拡張機能は、2 つの部分で構成されます。
| 部分 | 内容 | 含まれるもの |
|---|---|---|
| Gem(Rails エンジン) | spree_<name> Ruby gem | モデル、マイグレーション、Store/Admin API エンドポイント、シリアライザー、権限スコープ、ワークフック、サブスクライバー、プロバイダークラス、インテグレーション |
| ダッシュボードプラグイン(任意) | defineDashboardPlugin を使用する npm パッケージ | 管理画面、ナビゲーション項目、商品ページのウィジェット(Gem の Admin API エンドポイントと通信します) |
追加するビューはありません。Spree 6 には Rails 管理画面も Rails ストアフロントもありません。ストアフロントのページは、@spree/sdk を使用してストアフロントアプリ内に配置します。
Gem が適切な形でしょうか? カスタマイズを複数のアプリで共有する場合、または公開する場合に限り適切です。1 つのアプリで使用する場合は、同じコードを server/app/ に配置し、server/config/initializers/spree.rb に登録してください。詳しくは spree-customization を参照してください。
拡張 Gem のインストール
spree bundle add spree_reviews # or edit server/Gemfile, then `spree bundle install`
spree generate spree_reviews:install # convention: every extension ships <gem>:install
spree migrate
spree restart # Gemfile changes need a full restart (Ctrl+C `spree dev` if running)
ビルド済みイメージを使用する新規の create-spree-app プロジェクトでは、コンテナが server/ の Gemfile からビルドされるよう、spree eject を一度実行してください。
インストールジェネレーターは通常、マイグレーション(db/migrate/<ts>_<name>.<engine_name>.rb)をコピーし、イニシャライザーを追加する場合があります。拡張機能にダッシュボードプラグインがある場合は、apps/dashboard/ で pnpm add @scope/plugin も実行してください。プラグインは package.json の spree.dashboard.plugin マーカーによって自動検出されるため、ホスト側のコードを編集する必要はありません。
スキャフォールド済みプロジェクトの Gem
spree-starter のサーバー Gemfile(create-spree-app が server/ にクローンするもの)には、次の Gem が含まれています。
| Gem | 提供機能 |
|---|---|
spree | メタ Gem → spree_core + spree_api |
spree_dashboard | /dashboard で React 管理画面を提供 |
spree_emails | トランザクションメール |
spree_stripe | Stripe 決済 + Stripe Connect の出金プロバイダー |
spree_easypost | EasyPost の運送業者料金、ラベル、追跡(配送レート + フルフィルメントプロバイダー) |
spree_meilisearch | Meilisearch 検索プロバイダー(SpreeMeilisearch::SearchProvider) |
spree_opentelemetry | OpenTelemetry トレーシング(OTEL_* 環境変数が設定されるまで休止状態) |
spree_i18n | UI 翻訳 |
spree_adyen と spree_paypal_checkout は含まれていますが、コメントアウトされています。有効にする前に、各 Gem の gemspec/CHANGELOG で Spree 6 対応リリースを確認してください。Spree 4/5 時代のコミュニティ Gem(spree_reviews、spree_avatax_official、…)も同様です。まず spree_core の制約を確認してください。多くは移植が必要です(spree_admin なし、Spree::Adjustment なし、ステートマシンなし)。インテグレーションの一覧は https://spreecommerce.org/docs/integrations を参照してください。
複数ストア間での共有(1 つの商品/プロモーション/支払い方法を複数のストアで共有する機能)はコアにはありません。コアのレコードは 1 つのストアに属します。この機能には spree_multi_store 拡張機能を使用してください。
拡張機能の構築
gem install spree_extension -v '>= 2.0' # 1.x generates a Spree 5 scaffold (spree_admin, importmap) — don't use it
spree-extension create reviews # → ./spree_reviews
cd spree_reviews
2.x のスキャフォールドは spree_core + spree_api(>= 6.0.0.beta)に依存し、次のものを提供します。
lib/spree_reviews/engine.rb— 起動時および開発時の各リロード時に、すべてのapp/**/*_decorator*.rbを読み込むconfig.to_prepareと、コメントアウトされたadditional_permitted_attributes +=の例。config/initializers/spree.rb— 拡張機能の登録ファイル。ホストによって他のイニシャライザーと同様に起動時に読み込まれ、コメントアウトされたregister_scope、Spree.hooks.registerの例、およびサブスクライバーとレジストリ用のafter_initializeブロックを含みます。config/routes.rb—Spree::Core::Engine.add_routesフック、lib/spree_reviews/factories.rb、およびマイグレーションをコピーするinstallジェネレーター。
モデル
# db/migrate/20260901000000_create_spree_reviews.rb
create_table :spree_reviews do |t|
t.references :store, null: false, index: true, foreign_key: false
t.references :product, null: false, index: true, foreign_key: false
t.integer :rating, null: false
t.text :body
t.boolean :approved, null: false, default: false
t.timestamps
end
# app/models/spree/review.rb
module Spree
class Review < Spree.base_class
include Spree::SingleStoreResource # store filled in; API scopes to current store
has_prefix_id :review # review_k5nR8xLq on the wire
publishes_lifecycle_events # review.created / .updated / .deleted
belongs_to :product, class_name: 'Spree::Product' # required by default ("must exist")
validates :rating, presence: true, inclusion: { in: 1..5 }
scope :approved, -> { where(approved: true) }
self.whitelisted_ransackable_attributes = %w[rating approved]
end
end
規約:Spree.base_class、外部キー制約なし、関連付けには class_name、ストアスコープのデータ、プレフィックス付き ID、コールバックではなくイベントを使用します。
API
Store API コントローラーは Spree::Api::V3::Store::ResourceController を継承し、Admin API コントローラーは Spree::Api::V3::Admin::ResourceController を継承します。また、権限ゲートである scoped_resource :reviews と resource_permitted_attributes を必ず宣言してください。シリアライザーは Spree::Api::V3::BaseSerializer を継承します(admin シリアライザーは store シリアライザーを拡張します)。ルート:
# config/routes.rb
Spree::Core::Engine.add_routes do
namespace :api, defaults: { format: 'json' } do
namespace :v3 do
namespace(:store) { resources :reviews, only: [:index, :show] }
namespace(:admin) { resources :reviews }
end
end
end
コントローラーとシリアライザーの完全なテンプレート:spree-resource(spree:api_resource ジェネレーターが生成します)および spree-api-v3。将来コアにリソースが追加されたときに衝突しないよう、プラグイン所有のリソースには名前空間付きのパスを使用してください。
登録 — 場所とタイミング
登録は拡張機能の config/initializers/spree.rb に記述し、モデルに触れるコードはエンジンの config.to_prepare に記述します。コアは独自の config.after_initialize 内で一部のレジストリを = で代入し、それ以前に追加された内容を消去するため、タイミングが重要です。
| 登録 | 記述場所 |
|---|---|
Spree.payment_methods <<、Spree.fulfillment_providers <<、Spree.integrations <<、Spree.stock_splitters <<、Spree.tracking_carriers[...] =、Spree.adjusters <<、Spree.promotions.actions <<、Spree.*_authentication_strategies.add | Rails.application.config.after_initialize do … end — コアはこれらを独自の after_initialize 内で代入します。この処理は先に実行されます |
Spree.subscribers、Spree.delivery_rate_providers、tax_providers、payout_providers、digital_asset_providers、pricing_providers、inventory_providers、order_routing.rules/strategies、promotions.rules、Spree.reporting | アプリのイニシャライザーより前にシードされ、コアは連結します。どのタイミングでも動作しますが、統一的な安全策として after_initialize を推奨します(起動中にクラスをオートロードすることも避けられます) |
Spree.hooks.register(...)、Spree.permissions.register_scope(...)、Spree.search_provider = | イニシャライザーのトップレベル(文字列/レジストリベースで、リロードに安全です) |
Spree::Product.additional_permitted_attributes += [...]、デコレーターの読み込み、モデルクラスに触れる処理 | エンジンの config.to_prepare(開発環境でのリロード時に再実行されます) |
# config/initializers/spree.rb (inside the gem)
Spree.permissions.register_scope(:reviews, group: :catalog, resources: -> { [Spree::Review] })
Spree.hooks.register('products.activate.validate', 'SpreeReviews::RequireDescription')
Rails.application.config.after_initialize do
Spree.subscribers << SpreeReviews::ReviewRequestSubscriber # `bin/rails g spree:subscriber` adds these; pass the class — a String crashed production boot through 6.0.0.beta4
Spree.integrations << 'SpreeReviews::Integration' # if the gem needs per-store credentials
end
# lib/spree_reviews/engine.rb
module SpreeReviews
class Engine < Rails::Engine
require 'spree/core'
isolate_namespace Spree
engine_name 'spree_reviews'
config.to_prepare do
Dir.glob(SpreeReviews::Engine.root.join('app/**/*_decorator*.rb')) do |decorator|
Rails.configuration.cache_classes ? require(decorator) : load(decorator)
end
Spree::Product.additional_permitted_attributes += [:reviews_enabled] # += never << (frozen array)
end
end
end
ホストアプリも、server/config/initializers/spree.rb から同じ方法で同じ項目を登録します。コアが割り当てるレジストリには to_prepare だけでは不十分です。起動時には after_initialize より前に実行されるため、コアによって上書きされます。
各登録でできること:
register_scopeはread_reviews/write_reviewsを作成します。これらはスタッフのロール編集画面に表示され、シークレット API キーに付与できます。config/locales/en.ymlのen.spree.permissions_catalog.resources.reviews.{label,description}でラベルを設定してください。オプション:write: false、audiences:、read_only_for:。spree-auth-permissionsを参照してください。- ワークフローフックはコアのフロー内で実行され、処理を停止できます(
workflow.reject!('…'))。起動時のイーガーロード中にフックキーが検証されるため、タイプミスがあると起動に失敗します。spree-workflowsを参照してください。 - サブスクライバー(
Spree::Subscriber、subscribes_to 'order.placed')は、イベント発生後に処理を行います。spree-events-webhooksを参照してください。 - プロバイダーは、税、配送料、フルフィルメント、決済、検索、支払い、デジタルアセット、認証に対応します。各基底クラスとレジストリについては
spree-providersを参照してください。 Spree.dependenciesはコアのサービス/ワークフロー(*_workflowキー)を差し替えます。spree-dependenciesを参照してください。差し替えたワークフローはコアとの同期を保つ必要があるため、フックの使用を優先してください。
デコレーター(例:Spree::Product に has_many :reviews を追加する)は最後の手段として使用してください。spree-decorators を参照してください。
ダッシュボードプラグインのフロントエンド部分
npx @spree/cli plugin new reviews # or `spree plugin new reviews`
プラグインは defineDashboardPlugin(...) を呼び出してナビゲーション項目、ルート、スロットウィジェットを追加し、@spree/admin-sdk の client.request というエスケープハッチを使ってエンドポイントを読み書きします。spree.dashboard.plugin マーカーを付けた npm パッケージとして公開してください。利用者が pnpm add で追加すると、自動的に登録されます。ナビゲーションキー、ロケールキー、API パスには名前空間を付けてください(brands ではなく acme-brands)。キーが重複すると起動時にエラーになります。spree-dashboard-plugins を参照してください。
拡張機能のテスト
bundle exec rake test_app # generate spec/dummy (re-run after adding migrations)
bundle exec rspec
spree_dev_tools を使用した RSpec + Factory Bot を使用します。ファクトリーは lib/spree_reviews/factories.rb に配置してください。API のスペックでは、spree/api/testing_support/v3/base の共有コンテキスト('API v3 Store'、'API v3 Admin authenticated'、'API v3 Admin with custom permissions'、'API v3 Seller authenticated')を使用します。spree-testing を参照してください。
注意点
- 誤ったフェーズで登録すると、何も通知されずに見失われます。 決済方法、フルフィルメントプロバイダー、またはインテグレーションを
after_initializeの外で追加すると、起動時に消えてしまいます(コアがそれらの配列を再代入するためです)。症状:ダッシュボードで選択できない/「type must be registered」422。 additional_permitted_attributes << :xはFrozenErrorを発生させます。常に+=を使用してください。scoped_resourceのない Admin コントローラーは、リクエスト時にエラーになります。すべての Admin API コントローラーで、権限スコープを指定する必要があります。- マイグレーションは自動適用されません。 拡張機能を更新した後は、インストールジェネレーター(または
spree rails railties:install:migrations)を再実行してから、spree migrateを実行してください。spree migrateだけではコアのマイグレーションしかインストールされません。 - コピーしたマイグレーションの名前は変更しないでください。
. <engine_name>.rbのサフィックス(※実際の形式は.<engine_name>.rb)によって、Rails はコピー済みのマイグレーションをスキップし、Spree の起動チェックは不足しているマイグレーションを検出します。 - 認証情報は ENV ではなく、
Spree::Integrationに保存してください(ストアごとに設定でき、:passwordの設定値はマスクされます)。マルチストアのアプリでは、ストアごとに異なるアカウントで支払いを行ったり、商品を発送したりするためです。 - 同じメソッドに 2 つのデコレーターを適用すると、最後に読み込まれたものが有効になります。拡張機能を組み合わせられるように、フックやイベントを優先してください。
- サブスクライバーのコードはホットリロードされますが、登録(イニシャライザー)を変更するには再起動が必要です。
さらに詳しく
- 拡張機能のチュートリアル:
node_modules/@spree/docs/dist/developer/contributing/creating-an-extension.md - プロバイダーとインテグレーション:
node_modules/@spree/docs/dist/developer/providers/overview.md - ダッシュボードプラグイン:
node_modules/@spree/docs/dist/developer/dashboard/plugins/{overview,scaffolding,distributing}.md - カスタマイズのクイックスタート:https://spreecommerce.org/docs/developer/customization/quickstart
- 関連スキル:
spree-customization、spree-providers、spree-workflows、spree-resource、spree-auth-permissions、spree-dashboard-plugins、spree-testing