Back to Spree

Normalize state → status

docs/plans/6.0-normalize-state-to-status.md

5.4.24.7 KB
Original Source

Normalize state → status

Status: Design finalized, implementation not started Target: Spree 6.0 Depends on: Cart/Order split (6.0-cart-order-split.md), Split Adjustments (6.0-split-adjustments.md) Author: Damian + Claude Last updated: 2026-03-16

Summary

Rename the state column to status on the five remaining models that still use it. Newer models already use status. Order and Adjustment state columns are removed entirely by other 6.0 plans. This finishes the normalization so every state machine in Spree uses status.

Problem

Spree has two conventions for the state machine column name:

  • Legacy models use state: Payment, Shipment, InventoryUnit, ReturnAuthorization, GiftCard
  • Newer models use status: Product, PriceList, PaymentSession, PaymentSetupSession, Import, ImportRow, Invitation

This inconsistency means developers must remember which column each model uses. API responses mix state and status fields. Ransack filters differ per model. The CLAUDE.md rule says "default column should be status, legacy models use state" — 6.0 is the window to eliminate the exception.

Current State

ModelCurrent column6.0 action
OrderstateRemoved (cart-order-split — no state machine on Order)
AdjustmentstateRemoved (split-adjustments — no state machine)
PaymentstateRename → status
ShipmentstateRename → status
InventoryUnitstateRename → status
ReturnAuthorizationstateRename → status
GiftCardstateRename → status
ProductstatusAlready correct
PriceListstatusAlready correct
PaymentSessionstatusAlready correct
PaymentSetupSessionstatusAlready correct
ImportstatusAlready correct
ImportRowstatusAlready correct
InvitationstatusAlready correct
ReturnItemreception_status, acceptance_statusAlready correct
Reimbursementreimbursement_statusAlready correct

Key Decisions (do not deviate without discussion)

  • status is the standard. All state machines use status as the column name.
  • Single migration renames all five columns at once.
  • Deprecation aliases (alias_attribute :state, :status) for one release to avoid breaking custom code that reads .state.
  • API responses use status everywhere. No more state field in serializers.
  • Order payment_state and shipment_state stay as-is. These are derived summary fields on Order, not state machine columns. Renaming them to payment_status/shipment_status is optional and lower priority.

Migration Path

Phase 1: Column renames

ruby
class RenameStateToStatus < ActiveRecord::Migration[7.2]
  def change
    rename_column :spree_payments, :state, :status
    rename_column :spree_shipments, :state, :status
    rename_column :spree_inventory_units, :state, :status
    rename_column :spree_return_authorizations, :state, :status
    rename_column :spree_gift_cards, :state, :status
  end
end

Phase 2: Model updates

For each of the five models:

  1. Update state_machine declaration:
ruby
# Before
state_machine initial: :pending do

# After
state_machine :status, initial: :pending do
  1. Add deprecation alias:
ruby
# Temporary — remove in 6.1
alias_attribute :state, :status
  1. Update any scopes or methods that reference the state column directly (e.g., where(state: 'shipped')where(status: 'shipped')).

Phase 3: Serializer + API updates

  • All serializers return status instead of state
  • Ransack filters updated: filter[status_eq]=shipped instead of filter[state_eq]=shipped

Phase 4: StateChange model update

Spree::StateChange records state transitions with name field (e.g., "payment", "shipment"). The previous_state and next_state columns stay as-is — they store values like "pending", "shipped", not column names.

Phase 5: Cleanup (6.1)

  • Remove alias_attribute :state, :status from all five models
  • Remove any remaining state references in specs and factories

Constraints on Current Work

  • Use status in all new code. Don't add new state references.
  • New state machines must use status column. This is already the rule in CLAUDE.md.
  • Ransack filters on new endpoints should use status. Existing v3 endpoints will be updated in this plan.

Open Questions

None.

References

  • CLAUDE.md rule: "State machines: default column status (legacy uses state)"
  • Related plan: 6.0-cart-order-split.md (removes Order.state entirely)
  • Related plan: 6.0-split-adjustments.md (removes Adjustment.state entirely)
  • Decision log: docs/plans/decisions.md (2026-03-16 entry)