From a192aef0a5dd24de8a3ffa83c137fc57c701824d Mon Sep 17 00:00:00 2001 From: Chris Andreae Date: Fri, 1 Dec 2023 13:10:49 +0900 Subject: [PATCH 1/2] Deserialization: visit attrs/assocs in declaration order Rather than in the order they appeared in the update hash. Additionally, removes the redundant checking that the `attributes` in the UpdateData are valid viewmodel members: UpdateData validates this itself during construction. --- .../active_record/update_operation.rb | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/view_model/active_record/update_operation.rb b/lib/view_model/active_record/update_operation.rb index 34975399..580d586a 100644 --- a/lib/view_model/active_record/update_operation.rb +++ b/lib/view_model/active_record/update_operation.rb @@ -81,15 +81,15 @@ def run!(deserialize_context:) viewmodel._list_attribute = reposition_to end + # Visit attributes and associations as much as possible in the order + # that they're declared in the view. + member_ordering = viewmodel.class._members.keys.each_with_index.to_h + # update user-specified attributes - valid_members = viewmodel.class._members.keys.map(&:to_s).to_set - bad_keys = attributes.keys.reject { |k| valid_members.include?(k) } - if bad_keys.present? - causes = bad_keys.map { |k| ViewModel::DeserializationError::UnknownAttribute.new(k, blame_reference) } - raise ViewModel::DeserializationError::Collection.for_errors(causes) - end + attribute_keys = attributes.keys.sort_by { |k| member_ordering[k] } + attribute_keys.each do |attr_name| + serialized_value = attributes[attr_name] - attributes.each do |attr_name, serialized_value| # Note that the VM::AR deserialization tree asserts ownership over any # references it's provided, and so they're intentionally not passed on # to attribute deserialization for use by their `using:` viewmodels. A @@ -101,7 +101,13 @@ def run!(deserialize_context:) end # Update points-to associations before save - points_to.each do |association_data, child_operation| + points_to_keys = points_to.keys.sort_by do |association_data| + member_ordering[association_data.association_name] + end + + points_to_keys.each do |association_data| + child_operation = points_to[association_data] + reflection = association_data.direct_reflection debug "-> #{debug_name}: Updating points-to association '#{reflection.name}'" @@ -138,7 +144,12 @@ def run!(deserialize_context:) # Update association cache of pointed-from associations after save: the # child update will have saved the pointer. - pointed_to.each do |association_data, child_operation| + pointed_to_keys = pointed_to.keys.sort_by do |association_data| + member_ordering[association_data.association_name] + end + + pointed_to_keys.each do |association_data| + child_operation = pointed_to[association_data] reflection = association_data.direct_reflection debug "-> #{debug_name}: Updating pointed-to association '#{reflection.name}'" From 3e349d87a9e7bb36f073338793146a0314fbb95f Mon Sep 17 00:00:00 2001 From: Chris Andreae Date: Fri, 1 Dec 2023 13:12:15 +0900 Subject: [PATCH 2/2] Update gem to 3.7.6 --- lib/iknow_view_models/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/iknow_view_models/version.rb b/lib/iknow_view_models/version.rb index 0234fe9b..45cd0e98 100644 --- a/lib/iknow_view_models/version.rb +++ b/lib/iknow_view_models/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module IknowViewModels - VERSION = '3.7.5' + VERSION = '3.7.6' end