关于 spree-admin
spree-admin 是面向开发者的技能,用于定制 Spree 5.x 中基于 Rails 的旧版管理界面,涵盖资源脚手架以及导航、表格、视图和控制器调整。
主要功能
- 01生成 CRUD 管理界面脚手架
- 02定制侧边栏导航
- 03配置表格列
- 04覆盖视图并注入局部模板
- 05使用管理界面表单辅助工具
适用场景
- 01为模型添加管理界面
- 02调整管理列表和导航
- 03通过自定义视图扩展管理页面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ spree/ agent-skills --skill spree-admin安装后在 Claude Code 中输入/spree-admin确认已加载。
详细介绍
Spree 旧版 Rails 管理后台(spree_admin)
以下命令使用 Spree CLI 形式(
spree …、Docker)。对于没有 CLI 的经典 Rails 应用(通常是 5.4 之前的版本),请使用spree-project技能中的原生映射——在应用根目录下使用bin/rails/bundle exec rake,路径不带backend/前缀。
管理后台是一个 Rails 引擎——使用 ERB 视图在服务器端渲染,通过 Stimulus + Turbo 提供交互功能,并使用 Tailwind 设置样式。(Spree 6.0 将引入基于 React 的新管理后台;在 Spree 5.x 中,spree_admin 就是管理后台。)
项目布局
Rails 管理后台位于 spree_admin gem 中,挂载在 /admin。可将其视作普通 Rails 应用:
spree_admin gem
├── app/
│ ├── controllers/spree/admin/ # admin controllers
│ ├── views/spree/admin/<resource>/ # ERB views per resource
│ ├── helpers/spree/admin/ # view helpers
│ ├── presenters/spree/admin/ # presenter pattern for complex views
│ ├── javascript/spree/admin/ # Stimulus controllers, importmap-managed
│ └── models/spree/admin/navigation* # nav + nav builder
└── lib/generators/spree/admin/
├── install/ # bin/rails g spree:admin:install
└── scaffold/ # bin/rails g spree:admin:scaffold
在宿主应用(backend/)中,可在 backend/app/ 下相同路径覆盖文件以进行自定义。Rails 视图路径解析会优先使用宿主应用中的文件,而非 gem 中的文件。
添加新的管理资源(单命令方式)
Spree 提供了管理后台脚手架生成器,可为任何模型生成完整的 CRUD 管理后台。在模型和迁移创建完成后(使用 spree:api_resource 或 spree:model):
spree rails g spree:admin:scaffold Spree::Brand
此命令会生成:
| 文件 | 用途 |
|---|---|
backend/app/controllers/spree/admin/brands_controller.rb | 继承自 Spree::Admin::ResourceController 的控制器 |
backend/app/views/spree/admin/brands/index.html.erb | 列表页(渲染 render_table @collection, :brands;列来自表格注册表) |
backend/app/views/spree/admin/brands/new.html.erb | 创建表单页 |
backend/app/views/spree/admin/brands/edit.html.erb | 编辑表单页 |
backend/app/views/spree/admin/brands/_form.html.erb | 共用表单局部模板 |
backend/config/initializers/spree_admin_brands_table.rb | 表格列注册 |
backend/config/initializers/spree_admin_brands_navigation.rb | 侧边栏导航注册 |
backend/config/routes.rb | 将 namespace :admin { resources :brands } 注入 add_routes 块 |
生成器还会将路由注入 backend/config/routes.rb 中的 Spree::Core::Engine.add_routes do 块(该块存在于 spree-starter 模板中)。如果你的 routes.rb 中没有这个块,请手动添加路由:
# backend/config/routes.rb
Rails.application.routes.draw do
Spree::Core::Engine.add_routes do
namespace :admin do
resources :brands
end
end
mount Spree::Core::Engine, at: '/'
end
应使用 add_routes(而不是原始的 Spree::Core::Engine.routes.append),这是受支持的机制——它可以防止应用重新加载时重复绘制路由。
(如果你使用 spree:api_resource 创建 API,API 路由与管理后台路由相互独立,位于不同的命名空间中。)
重启 Rails 以加载新的初始化器和路由:
spree restart
自定义侧边栏
侧边栏条目在初始化器中注册。示例:
# backend/config/initializers/spree_admin_brands_navigation.rb
Rails.application.config.after_initialize do
Spree.admin.navigation.sidebar.add :brands,
label: :brands, # i18n key or string
url: :admin_brands_path, # symbol → route helper, or string
icon: 'list', # Tabler icon name (https://tabler.io/icons)
position: 55, # lower = earlier in sidebar
active: -> { controller_name == 'brands' }, # when to highlight
if: -> { can?(:manage, Spree::Brand) } # CanCanCan visibility check
end
常见导航模式:
# Top-level item that opens a sub-menu
Spree.admin.navigation.sidebar.add :marketing, label: :marketing, position: 30 do |nav|
nav.add :promotions, label: :promotions, url: :admin_promotions_path, position: 10
nav.add :coupon_codes, label: :coupon_codes, url: :admin_coupon_codes_path, position: 20
end
# Remove an existing entry
Spree.admin.navigation.sidebar.remove :reports
# Reorder an existing entry
Spree.admin.navigation.sidebar.update :products, position: 5
完整的导航 API 位于 spree/admin/app/models/spree/admin/navigation.rb,需要时可查看源代码。
自定义管理后台表格
大多数管理后台列表页(Products、Orders、Promotions 等)都使用已注册的表格定义——请查看 gem 的 config/initializers/spree_admin_tables.rb,了解已注册的键(注意:Customers 页面注册为 :users;Payment Methods 等少数页面不使用表格注册表)。可通过初始化器添加、移除或重新排列列:
# backend/config/initializers/spree_admin_products_table_customization.rb
Rails.application.config.after_initialize do
# Add a column to the existing Products table
Spree.admin.tables.products.add :brand_name,
label: :brand, # i18n key
type: :string, # :string | :number | :date | :datetime | :money | :status | :link | :boolean | :image | :custom | :association
sortable: true,
filterable: true,
default: true, # visible by default (vs opt-in via column toggle)
position: 25
# Remove a column
Spree.admin.tables.products.remove :sku
# Update an existing column
Spree.admin.tables.products.update :name, label: :product_name
end
对于自行生成的表格(通过 spree:admin:scaffold),生成的初始化器会提供合理的默认值——name、created_at、updated_at。在其中添加特定于业务领域的列。
自定义列渲染:如果列的值不是直接属性,请在模型或 presenter/decorator 中定义方法。列的键(add 的第一个参数)默认用作查找方法;传入 method: 可指定其他方法名或接收记录的 lambda。例如,如果你在 Products 表格中添加 brand_name 列,请在 Product 模型或 presenter 中定义 brand_name:
# In your model or decorator
def brand_name
brand&.name
end
覆盖视图
将同路径的文件放入宿主应用,Rails 就会使用它。gem 提供 spree/admin/app/views/spree/admin/products/index.html.erb;你可以在 backend/app/views/spree/admin/products/index.html.erb 中覆盖它。
需要注意两点:
-
先复制完整文件,再进行编辑。部分覆盖不起作用——Rails 会完全采用宿主应用中的文件。使用
bundle show spree_admin查找 gem 中的视图源文件。 -
视图文件包含用于交互行为的
data-controllerStimulus 绑定。如果删除data-controller="…"属性,相关 JS 就会停止工作。除非你要明确替换这些绑定,否则请保留它们。
如需进行轻量级覆盖,请使用管理后台的具名注入点,而不是覆盖整个视图。视图会通过 render_admin_partials 渲染已注册的局部视图列表(例如 head、body_end、products_header、product_form)。创建局部视图(例如 backend/app/views/spree/admin/shared/_my_banner.html.erb),并在初始化程序中注册:
Rails.application.config.after_initialize do
Spree.admin.partials.body_end << 'spree/admin/shared/my_banner'
end
在控制台中使用 Spree.admin.partials.keys 列出所有注入点。
构建管理后台 UI——表单构建器、组件和辅助方法
编写管理后台视图或局部视图时(例如脚手架生成的资源表单、注入的 product_form 区块或覆盖的视图),请使用管理后台自己的 UI 规范,而不是原始 Rails 辅助方法——这样就能轻松获得一致的样式、标签、错误显示和 i18n。
表单构建器(重要)
每个管理后台 form_with 都会自动使用 Spree::Admin::FormBuilder(管理后台 BaseController 中的 default_form_builder)——无需进行任何设置:
<%= form_with model: [:admin, @brand] do |f| %>
<%= f.spree_text_field :name, required: true %>
<%= f.spree_text_field :code, help: "Leave blank to auto-generate" %>
<%= f.spree_money_field :price, currency: current_store.default_currency %>
<%= f.spree_collection_select :tax_category_id, Spree::TaxCategory.all, :id, :name,
{ include_blank: true, autocomplete: true }, {} %>
<%= f.spree_check_box :active %>
<%= f.spree_file_field :logo, width: 240, height: 240 %>
<% end %>
完整的方法集:spree_text_field、spree_number_field、spree_money_field(分隔符会根据区域设置调整,提交时会规范化为小数,并追加货币符号)、spree_email_field、spree_date_field、spree_datetime_field、spree_text_area(会自动调整高度)、spree_rich_text_area(Trix)、spree_select / spree_collection_select(传入 autocomplete: true 可启用可搜索下拉菜单——选项达到 20 个或以上时,任何选择框都可以使用它)、spree_check_box、spree_radio_button(传入明确的 :id,即可将标签绑定到指定单选按钮;否则会根据值匹配标签)、spree_file_field(支持拖放、预览、crop: true 和 allowed_file_types:)。
所有方法的常用选项:label:(字符串,或使用 false 隐藏标签)、required:(显示星号)、help:(字段下方的文本)、help_bubble:(标签旁的工具提示图标)、class:。验证错误会自动显示在字段下方;标签通过 i18n 解析(先查找 spree.<attribute>,再查找 activerecord.attributes.spree/<model>.<attribute>)。
UI 组件
由辅助方法渲染、符合管理后台设计系统的组件——请使用它们,而不是手写标记:
| 组件 | 辅助方法 |
|---|---|
| 下拉菜单 | dropdown { dropdown_toggle + dropdown_menu } |
| 对话框(模态框)/ 抽屉(侧边面板) | dialog_header、dialog_close_button、dialog_discard_button;drawer_header、drawer_close_button |
| 图标 | icon('plus') — Tabler 图标名称 |
| 带备用图像的图片 | spree_image_tag |
| 工具提示 | tooltip、help_bubble |
| 状态徽章 | active_badge(condition) |
| 头像、剪贴板复制、进度条 | render_avatar、clipboard_component / clipboard_button、progress_bar_component |
| 按店铺时区显示日期 | spree_date、spree_time、spree_time_ago、local_time |
值得了解的视图辅助方法
- 导航/链接:
link_to_with_icon、link_to_edit、link_to_delete(内置 Turbo 确认)、button、external_link_to、page_header_back_button - Turbo:
turbo_save_button_tag(提交时显示保存状态)、turbo_render_alerts、turbo_close_dialog - 上下文:
current_store、current_currency、try_spree_current_user、supported_currencies - 模型偏好设置:
preference_fields/preference_field_for— 自动为模型的preference :x声明渲染表单输入项(支付方式和商店设置表单就是这样构建的)
完整参考文档位于本地文档中:node_modules/@spree/docs/dist/developer/admin/form-builder.md、components.md 和 helper-methods.md。
装饰管理控制器
Spree 管理控制器是普通的 Rails 控制器 — 可以像装饰其他控制器一样装饰它们。使用 spree generate controller_decorator Spree::Admin::ProductsController 生成文件 — 它会生成 backend/app/controllers/spree/admin/products_controller_decorator.rb,其中包含 prepended 钩子和 prepend 配置(生成器会嵌套模块,并将完整限定的 prepend 行放在外部;这种手写的等效形式更紧凑):
# backend/app/controllers/spree/admin/products_controller_decorator.rb
module Spree::Admin::ProductsControllerDecorator
def self.prepended(base)
base.before_action :my_custom_check, only: [:create, :update]
end
private
def my_custom_check
# ...
end
end
Spree::Admin::ProductsController.prepend Spree::Admin::ProductsControllerDecorator
这比自定义导航/表格影响更大 — 只有在需要更改操作行为时才使用。请先确认订阅器(用于副作用)或服务替换(用于业务逻辑)是否可行。完整的自定义决策树请参阅 spree-project 技能。
Stimulus 控制器 — 管理界面交互
Rails 管理界面使用 Stimulus + Turbo 实现客户端交互。现有控制器位于 spree_admin/app/javascript/spree/admin/controllers/:
| 控制器 | 功能 |
|---|---|
sidebar_controller.js | 侧边栏切换 + 持久化 |
variants_form_controller.js | 在产品编辑页面管理变体 |
page_builder_controller.js | 拖放式 CMS 页面构建器 |
bulk_editor_controller.js | 多行表格编辑 |
dropdown_controller.js | 下拉菜单 |
要添加自己的 Stimulus 控制器,将其放在 backend/app/javascript/controllers/,并通过 importmap(backend/config/importmap.rb)注册。在视图中使用 data-controller="my-controller" 引用它。
对于 Turbo Streams(服务端推送的 UI 更新),与任何 Rails 7+ Hotwire 应用一样,渲染控制器中的 turbo_stream.*,并通过 ID 指定目标 frame。
决策树:要进行哪种管理界面更改?
| 想要…… | 使用 |
|---|---|
| 添加指向自有页面的侧边栏项目 | 在初始化程序中使用 Spree.admin.navigation.sidebar.add |
| 向管理表格添加列 | 在初始化程序中使用 Spree.admin.tables.<name>.add |
| 添加新的资源 CRUD 区块 | bin/rails g spree:admin:scaffold Spree::YourModel |
| 编写或编辑表单 | 使用 f.spree_* 表单构建器方法 — 参见上文“构建管理界面” |
| 添加模态框 / 下拉菜单 / 徽章 / 工具提示 | 使用组件辅助方法 — 参见上文“构建管理界面” |
| 更改现有页面的外观 | 覆盖 backend/app/views/spree/admin/... 中的视图 |
| 向控制器添加新操作 | 装饰器(最后手段 — 请先参阅 spree-project 技能) |
| 让表单字段支持交互 | Stimulus 控制器 + 视图中的 data-controller="..." |
| 向界面推送实时更新 | 通过订阅器或服务广播 Turbo Stream |
| 全局更改管理界面样式 | 编辑 backend/app/assets/tailwind/spree_admin.css(由安装程序创建)— 它从 app/assets/tailwind/spree/admin/index.css 导入 gem 的基础样式;在此添加 @theme 覆盖和自定义 Tailwind 样式 |
进一步阅读
- **管理后台源码:**运行
bundle show spree_admin查找已安装 gem 的路径。gem 根目录下的 README 介绍了设计理念。 - 自定义文档:
node_modules/@spree/docs/dist/developer/admin/介绍了相关模式。 - 导航 API:
Spree::Admin::Navigation源码——导航自定义的完整方法列表。 - **表格 API:**gem 内的
Spree::Admin::Table(app/models/spree/admin/table.rb)和Spree::Admin::Table::Column(app/models/spree/admin/table/column.rb)——列类型、选项以及排序/筛选详情。Spree.admin.tables背后的注册表是lib/spree/admin/engine.rb中的Spree::Admin::Engine::TablesEnvironment。 - 脚手架生成器:
bundle show spree_admin/lib/generators/spree/admin/scaffold/ 中包含可复制用于高级自定义的模板文件。 - 表单构建器 / 组件 / 辅助方法:
node_modules/@spree/docs/dist/developer/admin/form-builder.md、components.md、helper-methods.md——其中列出了上文“构建管理后台 UI”部分涉及的所有选项。