mcpField
S
spree-extensions

spree-extensions

github.com/spree開発10220 回インストール4 週間前に更新
リポジトリ

spree-extensions について

Spree 6の拡張機能を開発するためのスキルです。Rails engine gemを基本とし、任意でダッシュボードプラグインを追加できます。構成、APIリソース、登録、プロバイダー、テスト、連携時の注意点を扱います。

主な機能

  1. 01Rails engine構成の拡張gemを作成
  2. 02StoreおよびAdmin APIリソースを追加
  3. 03フック、プロバイダー、サブスクライバーを登録
  4. 04任意のダッシュボードプラグインを作成
  5. 05RSpecとFactory Botで拡張をテスト

活用シーン

  1. 01複数のSpreeアプリで共有するカスタマイズのパッケージ化
  2. 02ストア単位のリソースとAPIエンドポイントの追加
  3. 03決済またはフルフィルメントプロバイダーの連携
  4. 04ダッシュボードプラグインによるAdmin画面の追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/spree/agent-skills --skill spree-extensions

インストール後、Claude Code で/spree-extensionsを入力して読み込まれたか確認します。

詳細

Spree 拡張機能

コマンドでは spree CLI 形式を使用します(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_stripeStripe 決済 + Stripe Connect の出金プロバイダー
spree_easypostEasyPost の運送業者料金、ラベル、追跡(配送レート + フルフィルメントプロバイダー)
spree_meilisearchMeilisearch 検索プロバイダー(SpreeMeilisearch::SearchProvider)
spree_opentelemetryOpenTelemetry トレーシング(OTEL_* 環境変数が設定されるまで休止状態)
spree_i18nUI 翻訳

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.addRails.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

コメント