Class: Spree::Products::PrepareNestedAttributes
- Inherits:
-
Object
- Object
- Spree::Products::PrepareNestedAttributes
- Defined in:
- app/services/spree/products/prepare_nested_attributes.rb
Overview
Prepares nested attributes for product updates, handling multi-store scenarios and permissions.
This service ensures that when editing a product in one store, taxon associations from other stores are preserved. This prevents accidental data loss when a store admin updates product categories in their store without affecting other stores.
Variant removal is opt-in: only variants explicitly listed in the
removed_variant_ids param are marked for destruction (or collected for
discontinuation when they have completed orders). Variants merely absent from
variants_attributes are left untouched, so a partially rendered or broken
form can never silently mass-delete variants.
Instance Attribute Summary collapse
-
#variants_to_discontinue ⇒ Object
readonly
Returns the value of attribute variants_to_discontinue.
Instance Method Summary collapse
- #call ⇒ Object
-
#initialize(product, store, params, ability) ⇒ PrepareNestedAttributes
constructor
A new instance of PrepareNestedAttributes.
Constructor Details
#initialize(product, store, params, ability) ⇒ PrepareNestedAttributes
Returns a new instance of PrepareNestedAttributes.
28 29 30 31 32 33 34 |
# File 'app/services/spree/products/prepare_nested_attributes.rb', line 28 def initialize(product, store, params, ability) @product = product @store = store @params = params @ability = ability @variants_to_discontinue = [] end |
Instance Attribute Details
#variants_to_discontinue ⇒ Object (readonly)
Returns the value of attribute variants_to_discontinue.
26 27 28 |
# File 'app/services/spree/products/prepare_nested_attributes.rb', line 26 def variants_to_discontinue @variants_to_discontinue end |
Instance Method Details
#call ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'app/services/spree/products/prepare_nested_attributes.rb', line 36 def call extract_removed_variant_ids if params[:variants_attributes] params[:variants_attributes].each do |key, variant_params| existing_variant = variant_params[:id].presence && @product.variants.find_by(id: variant_params[:id]) # a re-submitted variant always wins over a removal request variants_to_remove.delete(variant_params[:id].to_s) if variant_params[:id].present? variant_params.delete(:price) # remove legacy price param if can_update_prices? backfill_price_ids!(variant_params, existing_variant) variant_params[:prices_attributes]&.each do |price_key, price_params| variant_params[:prices_attributes][price_key]['_destroy'] = '1' if price_params[:amount].blank? end else variant_params.delete(:prices_attributes) end variant_params[:option_value_variants_attributes] = update_option_value_variants(variant_params.delete(:options), existing_variant) variant_params.delete(:stock_items_attributes) unless can_update_stock_items? params[:variants_attributes].delete(key) if variant_params.blank? end params[:variants_attributes] = params[:variants_attributes].merge(removed_variants_attributes) params[:product_option_types_attributes] = product_option_types_params.merge(removed_product_option_types_attributes) elsif params[:master_attributes] params[:master_attributes].delete(:stock_items_attributes) unless can_update_stock_items? if can_update_prices? # If the master price is nil then mark it for destruction params.dig(:master_attributes, :prices_attributes)&.each do |price_key, price_params| params[:master_attributes][:prices_attributes][price_key]['_destroy'] = '1' if price_params[:amount].blank? end else params[:master_attributes].delete(:prices_attributes) end end params.delete(:legacy_product_publications_attributes) unless can?(:manage, Spree::ProductPublication) # ensure the product is owned by a store params[:store_id] = store.id if params[:store_id].blank? && product.store_id.blank? # The variants matrix was emptied: no variant rows re-submitted, removals sent instead. # Option types are detached only when the removal list covers every variant, so a # partial (possibly broken) submission never turns the product into a simple one. # Variants kept alive by discontinuation still count as removed from the matrix, # so the detachment can't hinge on any of them yielding a `_destroy` row. if params[:variants_attributes].blank? && variants_to_remove.any? && can_remove_variants? attributes = removed_variants_attributes params[:option_type_ids] = [] if removing_all_variants? && !params.key?(:option_type_ids) if attributes.any? params[:variants_attributes] = attributes params[:variants_attributes].permit! end end params end |