From 275326eaa65ef3a62cddd857d805d9d964b28e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Turbelin?= Date: Tue, 28 Oct 2025 19:13:26 +0100 Subject: [PATCH 1/4] Replace alias_attribute with alias_method --- app/models/customer.rb | 6 ++++-- app/models/spree/order.rb | 6 ++++-- app/models/subscription.rb | 6 ++++-- config/environments/test.rb | 3 --- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/models/customer.rb b/app/models/customer.rb index 476dbc95f8..b514c0e1d0 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -25,11 +25,13 @@ class Customer < ApplicationRecord before_destroy :update_orders_and_delete_canceled_subscriptions belongs_to :bill_address, class_name: "Spree::Address", optional: true - alias_attribute :billing_address, :bill_address + alias_method :billing_address, :bill_address + alias_method :billing_address=, :bill_address= accepts_nested_attributes_for :bill_address belongs_to :ship_address, class_name: "Spree::Address", optional: true - alias_attribute :shipping_address, :ship_address + alias_method :shipping_address, :ship_address + alias_method :shipping_address=, :ship_address= accepts_nested_attributes_for :ship_address validates :code, uniqueness: { scope: :enterprise_id, allow_nil: true } diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb index 0ba30064c5..160041bfff 100644 --- a/app/models/spree/order.rb +++ b/app/models/spree/order.rb @@ -35,10 +35,12 @@ module Spree belongs_to :created_by, class_name: "Spree::User", optional: true belongs_to :bill_address, class_name: 'Spree::Address', optional: true - alias_attribute :billing_address, :bill_address + alias_method :billing_address, :bill_address + alias_method :billing_address=, :bill_address= belongs_to :ship_address, class_name: 'Spree::Address', optional: true - alias_attribute :shipping_address, :ship_address + alias_method :shipping_address, :ship_address + alias_method :shipping_address=, :ship_address= has_many :state_changes, as: :stateful, dependent: :destroy has_many :line_items, -> { diff --git a/app/models/subscription.rb b/app/models/subscription.rb index 4509c1ac75..8e2df44bd6 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -24,8 +24,10 @@ class Subscription < ApplicationRecord has_many :proxy_orders, dependent: :destroy has_many :orders, through: :proxy_orders - alias_attribute :billing_address, :bill_address - alias_attribute :shipping_address, :ship_address + alias_method :billing_address, :bill_address + alias_method :billing_address=, :bill_address= + alias_method :shipping_address, :ship_address + alias_method :shipping_address=, :ship_address= accepts_nested_attributes_for :subscription_line_items, allow_destroy: true accepts_nested_attributes_for :bill_address, :ship_address diff --git a/config/environments/test.rb b/config/environments/test.rb index 8c7562aee0..9fd47d1c3e 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -79,9 +79,6 @@ Rails.application.configure do "Passing the class as positional argument", - # Spree::Order model aliases `bill_address`, but `bill_address` is not an attribute. Starting in Rails 7.2, alias_attribute with non-attribute targets will raise. Use `alias_method :billing_address, :bill_address` or define the method manually. (called from initialize at app/models/spree/order.rb:188) - "alias_attribute with non-attribute targets will raise", - # Spree::CreditCard model aliases `cc_type` and has a method called `cc_type=` defined. Starting in Rails 7.2 `brand=` will not be calling `cc_type=` anymore. You may want to additionally define `brand=` to preserve the current behavior. "model aliases", From cf4cd311b345a9f65e2c75a7a799a8474bdbc57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Turbelin?= Date: Fri, 31 Oct 2025 14:07:47 +0100 Subject: [PATCH 2/4] Use customer-nested params for Customer v1 API writing operations --- .../api/v1/customers_controller.rb | 9 +- spec/requests/api/v1/customers_spec.rb | 47 ++-- swagger/v1.yaml | 206 +++++++++--------- 3 files changed, 147 insertions(+), 115 deletions(-) diff --git a/app/controllers/api/v1/customers_controller.rb b/app/controllers/api/v1/customers_controller.rb index 5353c6d39f..d342f05ef8 100644 --- a/app/controllers/api/v1/customers_controller.rb +++ b/app/controllers/api/v1/customers_controller.rb @@ -88,17 +88,20 @@ module Api attributes = params.require(:customer).permit( :email, :enterprise_id, :code, :first_name, :last_name, - :billing_address, shipping_address: [ + :billing_address, + shipping_address: [ :phone, :latitude, :longitude, :first_name, :last_name, :street_address_1, :street_address_2, :postal_code, :locality, { region: [:name, :code], country: [:name, :code] }, - ] + ], + tags: [], ).to_h attributes.merge!(created_manually: true) - attributes.merge!(tag_list: params[:tags]) if params.key?(:tags) + tags = attributes.delete(:tags) + attributes.merge!(tag_list: tags) if tags.present? transform_address!(attributes, :billing_address, :bill_address) transform_address!(attributes, :shipping_address, :ship_address) diff --git a/spec/requests/api/v1/customers_spec.rb b/spec/requests/api/v1/customers_spec.rb index 9f158e1de4..0dea8f4a4e 100644 --- a/spec/requests/api/v1/customers_spec.rb +++ b/spec/requests/api/v1/customers_spec.rb @@ -173,15 +173,23 @@ RSpec.describe "Customers", swagger_doc: "v1.yaml", feature: :api_v1 do parameter name: :customer, in: :body, schema: { type: :object, - properties: CustomerSchema.writable_attributes, - required: CustomerSchema.required_attributes + properties: { + customer: { + type: :object, + properties: CustomerSchema.writable_attributes, + required: CustomerSchema.required_attributes + } + }, + required: ['customer'] } response "201", "Minimal customer created" do let(:customer) do { - email: "test@example.com", - enterprise_id: enterprise1.id.to_s + customer: { + email: "test@example.com", + enterprise_id: enterprise1.id.to_s + } } end schema '$ref': "#/components/schemas/customer" @@ -199,12 +207,15 @@ RSpec.describe "Customers", swagger_doc: "v1.yaml", feature: :api_v1 do response "201", "Example customer created" do let(:customer) do - CustomerSchema.writable_attributes.transform_values do |attribute| - attribute[:example] - end.merge( - enterprise_id: enterprise1.id, - ) + { + customer: CustomerSchema.writable_attributes.transform_values do |attribute| + attribute[:example] + end.merge( + enterprise_id: enterprise1.id, + ) + } end + schema '$ref': "#/components/schemas/customer" run_test! do @@ -223,9 +234,11 @@ RSpec.describe "Customers", swagger_doc: "v1.yaml", feature: :api_v1 do response "422", "Unpermitted parameter" do let(:customer) do { - email: "test@example.com", - enterprise_id: enterprise1.id.to_s, - allow_charges: true, + customer: { + email: "test@example.com", + enterprise_id: enterprise1.id.to_s, + allow_charges: true, + } } end schema '$ref': "#/components/schemas/error_response" @@ -347,8 +360,14 @@ RSpec.describe "Customers", swagger_doc: "v1.yaml", feature: :api_v1 do parameter name: :customer, in: :body, schema: { type: :object, - properties: CustomerSchema.writable_attributes, - required: CustomerSchema.required_attributes + properties: { + customer: { + type: :object, + properties: CustomerSchema.writable_attributes, + required: CustomerSchema.required_attributes + } + }, + required: ['customer'] } response "200", "Customer updated" do diff --git a/swagger/v1.yaml b/swagger/v1.yaml index a9305be001..837a15fcfa 100644 --- a/swagger/v1.yaml +++ b/swagger/v1.yaml @@ -347,57 +347,62 @@ paths: schema: type: object properties: - enterprise_id: - type: integer - example: 2 - first_name: - type: string - nullable: true - example: Alice - last_name: - type: string - nullable: true - example: Springs - code: - type: string - nullable: true - example: BUYER1 - email: - type: string - example: alice@example.com - tags: - type: array - items: - type: string - example: - - staff - - discount - billing_address: + customer: type: object - nullable: true - example: - shipping_address: - type: object - nullable: true - example: - phone: 0404 333 222 111 - latitude: -37.8173751 - longitude: 144.964803195704 - first_name: Alice - last_name: Springs - street_address_1: 1 Flinders Street - street_address_2: '' - postal_code: '1234' - locality: Melbourne - region: - code: Vic - name: Victoria - country: - code: AU - name: Australia + properties: + enterprise_id: + type: integer + example: 2 + first_name: + type: string + nullable: true + example: Alice + last_name: + type: string + nullable: true + example: Springs + code: + type: string + nullable: true + example: BUYER1 + email: + type: string + example: alice@example.com + tags: + type: array + items: + type: string + example: + - staff + - discount + billing_address: + type: object + nullable: true + example: + shipping_address: + type: object + nullable: true + example: + phone: 0404 333 222 111 + latitude: -37.8173751 + longitude: 144.964803195704 + first_name: Alice + last_name: Springs + street_address_1: 1 Flinders Street + street_address_2: '' + postal_code: '1234' + locality: Melbourne + region: + code: Vic + name: Victoria + country: + code: AU + name: Australia + required: + - enterprise_id + - email required: - - enterprise_id - - email + - customer "/api/v1/customers/{id}": get: summary: Show customer @@ -570,57 +575,62 @@ paths: schema: type: object properties: - enterprise_id: - type: integer - example: 2 - first_name: - type: string - nullable: true - example: Alice - last_name: - type: string - nullable: true - example: Springs - code: - type: string - nullable: true - example: BUYER1 - email: - type: string - example: alice@example.com - tags: - type: array - items: - type: string - example: - - staff - - discount - billing_address: + customer: type: object - nullable: true - example: - shipping_address: - type: object - nullable: true - example: - phone: 0404 333 222 111 - latitude: -37.8173751 - longitude: 144.964803195704 - first_name: Alice - last_name: Springs - street_address_1: 1 Flinders Street - street_address_2: '' - postal_code: '1234' - locality: Melbourne - region: - code: Vic - name: Victoria - country: - code: AU - name: Australia + properties: + enterprise_id: + type: integer + example: 2 + first_name: + type: string + nullable: true + example: Alice + last_name: + type: string + nullable: true + example: Springs + code: + type: string + nullable: true + example: BUYER1 + email: + type: string + example: alice@example.com + tags: + type: array + items: + type: string + example: + - staff + - discount + billing_address: + type: object + nullable: true + example: + shipping_address: + type: object + nullable: true + example: + phone: 0404 333 222 111 + latitude: -37.8173751 + longitude: 144.964803195704 + first_name: Alice + last_name: Springs + street_address_1: 1 Flinders Street + street_address_2: '' + postal_code: '1234' + locality: Melbourne + region: + code: Vic + name: Victoria + country: + code: AU + name: Australia + required: + - enterprise_id + - email required: - - enterprise_id - - email + - customer delete: summary: Delete customer tags: From e385b9f7080bd886f786b5d48292dd12a09a212d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Turbelin?= Date: Mon, 3 Nov 2025 10:32:26 +0100 Subject: [PATCH 3/4] Revert "Use customer-nested params for Customer v1 API writing operations" This reverts commit cf4cd311b345a9f65e2c75a7a799a8474bdbc57a. --- .../api/v1/customers_controller.rb | 9 +- spec/requests/api/v1/customers_spec.rb | 47 ++-- swagger/v1.yaml | 206 +++++++++--------- 3 files changed, 115 insertions(+), 147 deletions(-) diff --git a/app/controllers/api/v1/customers_controller.rb b/app/controllers/api/v1/customers_controller.rb index d342f05ef8..5353c6d39f 100644 --- a/app/controllers/api/v1/customers_controller.rb +++ b/app/controllers/api/v1/customers_controller.rb @@ -88,20 +88,17 @@ module Api attributes = params.require(:customer).permit( :email, :enterprise_id, :code, :first_name, :last_name, - :billing_address, - shipping_address: [ + :billing_address, shipping_address: [ :phone, :latitude, :longitude, :first_name, :last_name, :street_address_1, :street_address_2, :postal_code, :locality, { region: [:name, :code], country: [:name, :code] }, - ], - tags: [], + ] ).to_h attributes.merge!(created_manually: true) - tags = attributes.delete(:tags) - attributes.merge!(tag_list: tags) if tags.present? + attributes.merge!(tag_list: params[:tags]) if params.key?(:tags) transform_address!(attributes, :billing_address, :bill_address) transform_address!(attributes, :shipping_address, :ship_address) diff --git a/spec/requests/api/v1/customers_spec.rb b/spec/requests/api/v1/customers_spec.rb index 0dea8f4a4e..9f158e1de4 100644 --- a/spec/requests/api/v1/customers_spec.rb +++ b/spec/requests/api/v1/customers_spec.rb @@ -173,23 +173,15 @@ RSpec.describe "Customers", swagger_doc: "v1.yaml", feature: :api_v1 do parameter name: :customer, in: :body, schema: { type: :object, - properties: { - customer: { - type: :object, - properties: CustomerSchema.writable_attributes, - required: CustomerSchema.required_attributes - } - }, - required: ['customer'] + properties: CustomerSchema.writable_attributes, + required: CustomerSchema.required_attributes } response "201", "Minimal customer created" do let(:customer) do { - customer: { - email: "test@example.com", - enterprise_id: enterprise1.id.to_s - } + email: "test@example.com", + enterprise_id: enterprise1.id.to_s } end schema '$ref': "#/components/schemas/customer" @@ -207,15 +199,12 @@ RSpec.describe "Customers", swagger_doc: "v1.yaml", feature: :api_v1 do response "201", "Example customer created" do let(:customer) do - { - customer: CustomerSchema.writable_attributes.transform_values do |attribute| - attribute[:example] - end.merge( - enterprise_id: enterprise1.id, - ) - } + CustomerSchema.writable_attributes.transform_values do |attribute| + attribute[:example] + end.merge( + enterprise_id: enterprise1.id, + ) end - schema '$ref': "#/components/schemas/customer" run_test! do @@ -234,11 +223,9 @@ RSpec.describe "Customers", swagger_doc: "v1.yaml", feature: :api_v1 do response "422", "Unpermitted parameter" do let(:customer) do { - customer: { - email: "test@example.com", - enterprise_id: enterprise1.id.to_s, - allow_charges: true, - } + email: "test@example.com", + enterprise_id: enterprise1.id.to_s, + allow_charges: true, } end schema '$ref': "#/components/schemas/error_response" @@ -360,14 +347,8 @@ RSpec.describe "Customers", swagger_doc: "v1.yaml", feature: :api_v1 do parameter name: :customer, in: :body, schema: { type: :object, - properties: { - customer: { - type: :object, - properties: CustomerSchema.writable_attributes, - required: CustomerSchema.required_attributes - } - }, - required: ['customer'] + properties: CustomerSchema.writable_attributes, + required: CustomerSchema.required_attributes } response "200", "Customer updated" do diff --git a/swagger/v1.yaml b/swagger/v1.yaml index 837a15fcfa..a9305be001 100644 --- a/swagger/v1.yaml +++ b/swagger/v1.yaml @@ -347,62 +347,57 @@ paths: schema: type: object properties: - customer: + enterprise_id: + type: integer + example: 2 + first_name: + type: string + nullable: true + example: Alice + last_name: + type: string + nullable: true + example: Springs + code: + type: string + nullable: true + example: BUYER1 + email: + type: string + example: alice@example.com + tags: + type: array + items: + type: string + example: + - staff + - discount + billing_address: type: object - properties: - enterprise_id: - type: integer - example: 2 - first_name: - type: string - nullable: true - example: Alice - last_name: - type: string - nullable: true - example: Springs - code: - type: string - nullable: true - example: BUYER1 - email: - type: string - example: alice@example.com - tags: - type: array - items: - type: string - example: - - staff - - discount - billing_address: - type: object - nullable: true - example: - shipping_address: - type: object - nullable: true - example: - phone: 0404 333 222 111 - latitude: -37.8173751 - longitude: 144.964803195704 - first_name: Alice - last_name: Springs - street_address_1: 1 Flinders Street - street_address_2: '' - postal_code: '1234' - locality: Melbourne - region: - code: Vic - name: Victoria - country: - code: AU - name: Australia - required: - - enterprise_id - - email + nullable: true + example: + shipping_address: + type: object + nullable: true + example: + phone: 0404 333 222 111 + latitude: -37.8173751 + longitude: 144.964803195704 + first_name: Alice + last_name: Springs + street_address_1: 1 Flinders Street + street_address_2: '' + postal_code: '1234' + locality: Melbourne + region: + code: Vic + name: Victoria + country: + code: AU + name: Australia required: - - customer + - enterprise_id + - email "/api/v1/customers/{id}": get: summary: Show customer @@ -575,62 +570,57 @@ paths: schema: type: object properties: - customer: + enterprise_id: + type: integer + example: 2 + first_name: + type: string + nullable: true + example: Alice + last_name: + type: string + nullable: true + example: Springs + code: + type: string + nullable: true + example: BUYER1 + email: + type: string + example: alice@example.com + tags: + type: array + items: + type: string + example: + - staff + - discount + billing_address: type: object - properties: - enterprise_id: - type: integer - example: 2 - first_name: - type: string - nullable: true - example: Alice - last_name: - type: string - nullable: true - example: Springs - code: - type: string - nullable: true - example: BUYER1 - email: - type: string - example: alice@example.com - tags: - type: array - items: - type: string - example: - - staff - - discount - billing_address: - type: object - nullable: true - example: - shipping_address: - type: object - nullable: true - example: - phone: 0404 333 222 111 - latitude: -37.8173751 - longitude: 144.964803195704 - first_name: Alice - last_name: Springs - street_address_1: 1 Flinders Street - street_address_2: '' - postal_code: '1234' - locality: Melbourne - region: - code: Vic - name: Victoria - country: - code: AU - name: Australia - required: - - enterprise_id - - email + nullable: true + example: + shipping_address: + type: object + nullable: true + example: + phone: 0404 333 222 111 + latitude: -37.8173751 + longitude: 144.964803195704 + first_name: Alice + last_name: Springs + street_address_1: 1 Flinders Street + street_address_2: '' + postal_code: '1234' + locality: Melbourne + region: + code: Vic + name: Victoria + country: + code: AU + name: Australia required: - - customer + - enterprise_id + - email delete: summary: Delete customer tags: From b2d7d797d9ad6f22c8dfa35908765fe875fd4191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Turbelin?= Date: Mon, 3 Nov 2025 11:33:58 +0100 Subject: [PATCH 4/4] Use wrap_parameters to handle address params on Customer v1 API --- app/controllers/api/v1/customers_controller.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/customers_controller.rb b/app/controllers/api/v1/customers_controller.rb index 5353c6d39f..4e3efb75b8 100644 --- a/app/controllers/api/v1/customers_controller.rb +++ b/app/controllers/api/v1/customers_controller.rb @@ -8,6 +8,10 @@ module Api include AddressTransformation include ExtraFields + wrap_parameters :customer, include: + Customer.attribute_names + + [:billing_address, :shipping_address] + skip_authorization_check only: :index before_action :authorize_action, only: [:show, :update, :destroy] @@ -88,7 +92,8 @@ module Api attributes = params.require(:customer).permit( :email, :enterprise_id, :code, :first_name, :last_name, - :billing_address, shipping_address: [ + :billing_address, + shipping_address: [ :phone, :latitude, :longitude, :first_name, :last_name, :street_address_1, :street_address_2,