ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Spree 5.5→6.0 重构指南:display_on 三态字段收敛为 storefront_visible 布尔值

Spree 5.5→6.0 重构指南:display_on 三态字段收敛为 storefront_visible 布尔值 Spree 5.5→6.0 重构指南display_on 三态字段收敛为 storefront_visible 布尔值【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree在 Spree面向 B2B、Marketplace 与多租户场景的开源电商平台中支付与配送方式长期用一个三态字符串字段display_onboth/front_end/back_end控制可见性。本文基于仓库内的规划文档 5.5-6.0-display-on-to-boolean.md完整梳理这次已落地Status: Implemented, 2026-08-19的重构为什么三态收敛为布尔值storefront_visible、5.5 版本的 API 桥接层如何设计、6.0 的数据库迁移如何原子化完成以及模型、Admin API v3、TypeScript SDK 与 Admin SPA 各层的具体实现证据。读完后你能掌握 Spree 先加别名、后改 schema 的字段重命名迁移模式并能在自己的扩展中正确使用新字段。背景display_on 三态字段的设计缺陷在 5.4 时代的 Spree 中Spree::PaymentMethod和Spree::ShippingMethod6.0 更名为DeliveryMethod的表结构里都有一个display_on字符串列取值域为both | front_end | back_end并共同 include 一个名为Spree::DisplayOn的 concern提供scope :available仅bothscope :available_on_front_endfront_endbothscope :available_on_back_endback_endbothvalidates :display_on, presence: true, inclusion: { in: DISPLAY.map(:to_s) }available_on_front_end?实例谓词这次重构的动机来自一个业务判断front_end仅前台可见、后台不可见这个状态并不对应任何真实工作流——后台运营人员必须能看到每一种支付/配送方式才能查询历史交易、处理退款、编辑订单。既然front_end是死状态剩下的both与back_end两个状态就可以无损地坍缩成一个布尔值back_end→storefront_visible: falseboth以及遗留的front_end→storefront_visible: true规划文档的关键决策原文 Key Decisions 章节包括用布尔值而非三态与 custom-fields 重命名计划5.4-6.0-custom-fields-rename.md采用同一套推理。命名storefront_visible而非available_on_storefront整个产品对同一概念使用同一个词与 custom fields 计划保持一致。默认值为true大多数支付/配送方式是面向顾客的back_end只是少数例外手动支票录入、内部电汇、仅退款用途的方式。front_end边缘数据一律映射为true与 custom-fields 计划的数据迁移规则一致。5.5 的迁移是非破坏性的不做数据迁移、不删列读display_on的代码继续工作读storefront_visible的代码拿到布尔值。两阶段落地路线重构分两个版本交付每个版本的目标不同阶段一5.5API 桥接 alias_attributeshim无 schema 变更在两个模型上新增storefront_visible读写访问器代理到既有的display_on列Admin API v3 的读与写都以storefront_visible为规范字段写请求同时容忍display_on保证树外集成在 5.5 周期内继续工作遗留 Rails 后台引擎spree/admin继续通过表单辅助方法写display_on该路径到 6.0 才迁移SDK 只发布storefront_visibleAdmin SPA 使用StorefrontVisibleSwitch组件数据库零改动。规划文档给出的 5.5 桥接实现是扩展Spree::DisplayOnconcern当时三个调用方PaymentMethod、ShippingMethod、MetafieldDefinition都 include 它加在 concern 里可让三个模型自动继承# spree/core/app/models/concerns/spree/display_on.rb (5.5) module Spree module DisplayOn extend ActiveSupport::Concern DISPLAY [:both, :front_end, :back_end] included do scope :available, - { where(display_on: [:both]) } scope :available_on_front_end, - { where(display_on: [:front_end, :both]) } scope :available_on_back_end, - { where(display_on: [:back_end, :both]) } # New canonical scopes (5.5 → 6.0). scope :storefront_visible, - { where.not(display_on: back_end) } scope :admin_only, - { where(display_on: back_end) } validates :display_on, presence: true, inclusion: { in: DISPLAY.map(:to_s) } def available_on_front_end? display_on front_end || display_on both end # 5.5 bridge — storefront_visible is the canonical wire field. # back_end → false; everything else → true. def storefront_visible display_on ! back_end end def storefront_visible(value) self.display_on ActiveModel::Type::Boolean.new.cast(value) ? both : back_end end end end end往返语义清晰读时back_end→false其余both或遗留的front_end→true写时true→bothfalse→back_endround-trip 无损。Spree::MetafieldDefinition原本按 custom-fields 计划单独定义了同名访问器concern 提供后这些副本可以删除该协调通过对应计划的 checklist 完成。同期序列化器侧把线上字段从字符串换成布尔# Before typelize display_on: :string attributes :display_on # After (5.5) — wire field is the boolean only typelize storefront_visible: :boolean attributes :storefront_visibledisplay_on从此不再出现在 API 响应中DB 列仍保留只是 API 表面变了。允许参数方面payment_method_attributes与shipping_method_attributes在 5.5 周期同时保留:display_on与:storefront_visibleconcern 上的访问器把两者收敛到同一底层列。文档明确警告客户端应提交其一同时提交两者是未定义行为取决于 JSON 键顺序storefront_visible是规范名display_on只是 6.0 即删的兼容 shim。阶段二6.0schema 变更 删除 concern6.0 把display_on字符串列替换为storefront_visible布尔列default: true, null: false删除Spree::DisplayOnconcern三个调用方至此全部迁完是干净的一次性清除并移除display_onAPI 别名。这一阶段属于 6.0 的模型重命名波次与Shipment → Fulfillment、ShippingMethod → DeliveryMethod、Metafield → CustomField同期推进配送侧上下文见 6.0-fulfillment-and-delivery.md。6.0 迁移实现数据转换内嵌于 migration以 PaymentMethod 实际交付的迁移 20260819000001_replace_payment_method_display_on_with_storefront_visible.rb 为例class ReplacePaymentMethodDisplayOnWithStorefrontVisible ActiveRecord::Migration[8.1] # Payment methods are the last host of the tri-state display_on column # (docs/plans/5.5-6.0-display-on-to-boolean.md). Only back_end ever meant # hide from the storefront; both and the legacy front_end-only value # collapse to true. def up add_column :spree_payment_methods, :storefront_visible, :boolean, default: true, null: false execute(~SQL.squish) UPDATE spree_payment_methods SET storefront_visible #{connection.quoted_false} WHERE display_on back_end SQL remove_column :spree_payment_methods, :display_on end def down add_column :spree_payment_methods, :display_on, :string, default: both execute(~SQL.squish) UPDATE spree_payment_methods SET display_on back_end WHERE storefront_visible #{connection.quoted_false} SQL remove_column :spree_payment_methods, :storefront_visible end end迁移注释与规划文档给出了一个反直觉但重要的工程决策数据转换写在 migration 里而不是 rake task。惯例上数据转换放 rake task的前提是任务执行时源列还在而这里的 migration 在同一条语句里删掉了display_on后续任务将无列可读。又因为除back_end外所有值都保留列默认值true所以一条窄UPDATE即可且down方向对称可逆。三个模型的实际切换时间线见文档 Status 行DeliveryMethod2026-08-05先切——它的三态DISPLAY_ON_*费率过滤常量改成了符号DeliveryMethod::STOREFRONT/BACKOFFICEmigration 只加列回填留给spree:migrate_shipping_to_delivery转换后清空display_on重跑安全CustomFieldDefinition2026-08-09作为 metafields 重命名的一部分PaymentMethod2026-08-19即上面这条 migration。当前源码中的模型层实现PaymentMethod真实布尔列 规范 scopesspree/core/app/models/spree/payment_method.rb 展示了 6.0 的最终形态scope :active, - { where(active: true).order(position: :asc) } # Every tri-state display_on value passed the old filter, so availability # only ever meant active. scope :available, - { active } ... # Customer-facing methods vs backoffice-only ones (manual check entry, # internal wire transfers). The backoffice always sees every method. scope :storefront_visible, - { where(storefront_visible: true) } scope :admin_only, - { where(storefront_visible: false) } # Real column, so admin clients filter it directly — no ransacker needed. self.whitelisted_ransackable_attributes %w[storefront_visible] ... validates :storefront_visible, inclusion: { in: [true, false] }几个值得注意的实现细节storefront_visible是真实列因此管理端客户端可以直接按列过滤whitelisted_ransackable_attributes白名单里注册了它不需要写 ransacker 方法。旧availablescope 的语义修正源码头注释说明旧三态值都能通过available过滤所以该 scope 实际只等价于active——布尔化之后这个历史含糊被显式记录。校验改为布尔包含式inclusion: { in: [true, false] }配合列的null: false, default: true杜绝了旧presence 枚举字符串校验。同时模型保留了 6.1 才移除的弃用入口payment_method.rb#L291-L307# deprecated Use {#storefront_visible?}; removed in 6.1. def available_on_front_end? Spree::Deprecation.warn(Spree::PaymentMethod#available_on_front_end? is deprecated and will be removed in Spree 6.1. Use #storefront_visible? instead.) storefront_visible? end # deprecated Use {#storefront_visible}; removed in 6.1. def display_on Spree::Deprecation.warn(Spree::PaymentMethod#display_on is deprecated and will be removed in Spree 6.1. Use #storefront_visible instead.) storefront_visible? ? both : back_end end # deprecated Use {#storefront_visible}; removed in 6.1. def display_on(value) Spree::Deprecation.warn(Spree::PaymentMethod#display_on is deprecated and will be removed in Spree 6.1. Use #storefront_visible instead.) self.storefront_visible value.to_s ! back_end end这与规划文档每个模型保留display_on作为弃用读写入口直到 6.1的约束一致读时反向翻译回旧字符串词表写时把任意非back_end值折成true。DeliveryMethod受众过滤从整数常量改为符号spree/core/app/models/spree/delivery_method.rb 中可以看到费率报价的受众常量已完成切换# Audience a rate refresh is quoting for: the storefront sees only # customer-facing methods, the backoffice sees every method. STOREFRONT :storefront BACKOFFICE :backoffice旧的整数常量DISPLAY_ON_FRONT_END 1/DISPLAY_ON_BACK_END 2保留为弃用别名delivery_method.rb#L28-L31而 normalize_audience 负责把旧调用方安全地映射到新词汇表def self.normalize_audience(audience) case audience when STOREFRONT, BACKOFFICE then audience when DISPLAY_ON_FRONT_END, DISPLAY_ON_BACK_END Spree::Deprecation.warn(...Use #{STOREFRONT.inspect} / #{BACKOFFICE.inspect} instead.) audience DISPLAY_ON_BACK_END ? BACKOFFICE : STOREFRONT else raise ArgumentError, unknown delivery audience #{audience.inspect} ... end end注意这里的防御性设计未知受众直接raise而不是悄悄按前台口径收窄报价集——typo must not narrow the offer set unnoticed。配套的实例方法 available_to? 则体现了规划文档中的核心约束后台看到一切def available_to?(audience) case self.class.normalize_audience(audience) when BACKOFFICE then true else storefront_visible? end endDeliveryMethod 同样拥有布尔属性与规范 scopesdelivery_method.rb#L67、L91-L92、L118attribute :storefront_visible, :boolean, default: true ... scope :storefront_visible, - { where(storefront_visible: true) } scope :admin_only, - { where(storefront_visible: false) } ... self.whitelisted_ransackable_attributes %w[storefront_visible available_to_sellers seller_id]其弃用壳display_on/display_ondelivery_method.rb#L453-L463与available_to_display?的处置方式与 PaymentMethod 完全对称。API 层序列化器与允许参数Admin API v3 的序列化器只发布布尔字段。以 Admin::PaymentMethodSerializer 为例typelize active: :boolean, ... storefront_visible: :boolean, ... attributes :metadata, :active, :auto_capture, :capture_method, :resolved_capture_method, :storefront_visible, :position, created_at: :iso8601, updated_at: :iso8601display_on已彻底不在 wire 上。控制器侧的允许参数只暴露新字段如 admin/payment_methods_controller.rb#L55 中的:name, :description, :active, :storefront_visible, :auto_capture, :capture_method, :position, ...配送方式控制器admin/delivery_methods_controller.rb#L131同样在:pickup_point_provider, :rate_provider, :storefront_visible, ...中注册了该字段。Store API 侧则从未把display_on作为线上字段暴露过规划文档 Resolved Questions 一节确认Store 的配送方式接口只是服务端按它过滤因此不需要 Store API 桥接层。SDK 与 Admin SPA 的配套变更TypeScript 侧按规划一次性删除旧类型而非渐进弃用admin SDK 在 5.5 周期仍是nexttag、pre-1.0树外 TS 消费者极少删除优于弃用// Before export type DisplayOnValue both | front_end | back_end export interface PaymentMethod { display_on: DisplayOnValue } // After (5.5) — boolean only; legacy types removed export interface PaymentMethod { storefront_visible: boolean }DisplayOnValue等类型被整体移除create/update 参数形状只暴露storefront_visible?: boolean。服务器写请求仍接受display_on但 SDK 不再为其建模需要发送遗留字段的 TS 调用方可自行断言。Admin SPA 侧提供了两个配套 UI 组件。表单控件是 StorefrontVisibleSwitch——一个带标签的Switch默认文案 Visible on storefront带说明文本组件 JSDoc 明确标注它是 Canonical 5.5 Visible on storefront control供所有在 API 上暴露storefront_visible的资源使用接入方式与其他表单项一致StorefrontVisibleSwitch control{form.control} namestorefront_visible /表格单元则复用既有的 Active 列视觉语言按规划文档建议渲染为ActiveBadge active{pm.storefront_visible} activeLabelVisible inactiveLabelAdmin only /旧的三态DisplayOnSelect不存在于 6.0 代码库——它是在引入 Switch 的同一变更中被删除的。迁移路径与调用方行动清单对商户 / 托管方5.5 → 6.0升级到 5.5无需任何操作。display_on继续可用storefront_visible开始可用升级到 6.0运行bin/rails db:migrate。支付方式与自定义字段定义在各自 migration 内原子转换不存在一半转换的中间窗口也没有额外的 rake 任务配送方式的转换在spree:migrate_shipping_to_delivery中完成已包含在 5.6 → 6.0 升级清单里。对消费 Admin / Store API 的集成方5.5 起改为读布尔字段storefront_visible两个字段曾短暂并行出现5.5 起create/update 调用改提交storefront_visible6.0 起display_on从响应与参数形状中消失删除所有读写它的代码。对扩展 / 插件开发者直接读payment_method.display_on的扩展代码改为payment_method.storefront_visible6.0 中旧入口只发弃用告警where(display_on: back_end)这类查询改用新 scopeadmin_only或where(storefront_visible: false)6.0 中列已删除任何残留的display_on数据库级引用都会直接失败。约束与边界决策规划文档对后续开发立下了三条约束Constraints on Current Work这些约束决定了 Spree 可见性系统的长期形态storefront_visible是唯一规范名。display_on仅作为树外代码的弃用读写入口存在于各模型上Spree 内部代码不得再调用它新模型不得引入可见性 concern。从源码结构看PaymentMethod与DeliveryMethod各自内联了两行 scope 加校验——四行代码的三份拷贝从未证明过这层间接抽象的必要性这正是 6.0 选择删除 concern 而非改写的理由只有当第四个调用方出现时才重新讨论后台永远看全部。storefront_visible只过滤顾客端表面管理端列表不得应用该过滤旧的available_on_back_endscope返回back_endboth没有布尔等价物被直接丢弃而不是强行翻译——这也解释了为何 PaymentMethod 的availablescope 只剩active语义。规划文档的 Resolved Questions 一节还澄清了两点available_on_front_end?谓词以弃用壳形式保留在 PaymentMethod 上委托storefront_visible?6.1 移除而 DeliveryMethod 与 CustomFieldDefinition 从未继承该谓词Store API 不需要ShippingMethod的display_on桥接因为它从来不是线上字段。可见性系统简化相关的后续决策沉淀在 docs/plans/decisions.md 中。延伸阅读本次重构的完整规划与决策记录docs/plans/5.5-6.0-display-on-to-boolean.md同一桥接模式的先行者Metafield → CustomFielddocs/plans/5.4-6.0-custom-fields-rename.mdShippingMethod → DeliveryMethod 重命名背景docs/plans/6.0-fulfillment-and-delivery.md核心模型实现PaymentMethod、DeliveryMethod数据迁移ReplacePaymentMethodDisplayOnWithStorefrontVisible序列化器与控制器Admin::PaymentMethodSerializer、admin payment methods controllerAdmin SPA 组件StorefrontVisibleSwitch【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表