-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[RUBY-3387] Fix duplicate storage of govpay status by refactoring `Sa…
…feCopyAttributesService` - Implement `safe_copy_attributes` method to handle attribute copying more efficiently. - Introduce private helper methods `get_attributes`, `filter_attributes`, and `find_embedded_relation` to modularize logic. - Update specs to cover new functionality, including handling of Hash and BSON::Document sources. - Ensure only valid attributes are copied, and embedded documents are processed correctly. [RUBY-3387] Refactor `SafeCopyAttributesService` to streamline attribute copying - Removed unused parameters `embedded_documents` and `attributes_to_exclude` from the `SafeCopyAttributesService`. - Simplified the logic for copying attributes, focusing on filtering and processing embedded documents directly within the `copy_attributes` method. - Updated related specs to reflect changes in the service, ensuring correct attributes are copied and non-existent attributes are excluded. [RUBY-3387] Implement exclusion of attributes in SafeCopyAttributesService - Updated `SafeCopyAttributesService` to allow exclusion of specified attributes during the copy process. - Modified `can_copy_data_from_registration` to pass `attributes_to_exclude` option. - Enhanced `filter_attributes` method to exclude specified attributes. - Adjusted tests in `safe_copy_attributes_service_spec` to cover new exclusion functionality. - Removed redundant embedded document copying logic from `past_registration` and `registration_completion_service`. [RUBY-3387] Fix duplicate storage of govpay status in `SafeCopyAttributesService` - Updated the service to correctly handle source relation data with both camelCase and snake_case keys. - Adjusted the logic to prevent storing attributes not present on the model, specifically `govpayStatus`. - Enhanced tests to verify that `govpayStatus` is not included in the result while valid attributes like `currency` are correctly processed. [RUBY-3387] Rubocop changes - Corrected the logic to prevent `govpayStatus` from being stored twice by refining the attribute matching process. - Improved code readability by adding parentheses for variable assignments within conditional statements. - Removed redundant code and fixed indentation issues. - Updated tests to reflect changes in attribute presence checks, ensuring `govpayStatus` is not included if not present in the order model. [RUBY-3387] Refactor attribute copying in `SafeCopyAttributesService` - Simplified the `copy_attributes` method to improve readability and maintainability. - Introduced `extract_attributes`, `filter_attributes`, and `process_embedded_relations` helper methods for better structure. - Enhanced handling of embedded relations by adding `find_relation_data` to support different naming conventions. - Improved error handling for unsupported source types. [RUBY-3387] Fix duplicate storage of `govpayStatus` in SafeCopyAttributesService - Updated `SafeCopyAttributesService` to exclude relations specified in `attributes_to_exclude` when copying attributes. - Refactored method to find matching attribute keys based on naming conventions. - Added tests to ensure excluded relations are not copied and that copyable attributes are correctly included. [RUBY-3387] Fix attribute comparison in specs to ignore `_id` field Updated tests in `past_registration_spec.rb` and `registration_completion_service_spec.rb` to compare attributes excluding the `_id` field as new implementation of SafeCopyAttributes does not copy the id field of the embedded documents like the old one did Chore/ruby 3409 mongoid reference one (#1574) https://eaflood.atlassian.net/browse/RUBY-3409 [RUBY-3387] Update spec to reference registered address as company address was removed [RUBY-3387] Add documentation to `SafeCopyAttributesService` in `safe_copy_attributes_service.rb` Enhanced the `SafeCopyAttributesService` with detailed comments explaining its functionality, including how it safely copies attributes between instances and handles embedded relations.
- Loading branch information
Showing
29 changed files
with
264 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 0 additions & 63 deletions
63
app/models/concerns/waste_carriers_engine/can_reference_single_document_in_collection.rb
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 75 additions & 13 deletions
88
app/services/waste_carriers_engine/safe_copy_attributes_service.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,94 @@ | ||
# frozen_string_literal: true | ||
|
||
module WasteCarriersEngine | ||
class SafeCopyAttributesService < BaseService | ||
# This responsible for safely copying attributes from a source instance of | ||
# one class to a new instance of the targeted class. It ensures that only attributes | ||
# that are defined in the target class are copied, excluding any specified attributes. | ||
# The service also handles embedded relations recursively, processing nested | ||
# attributes according to the target class definitions. | ||
|
||
attr_accessor :source_instance, :target_class, :embedded_documents, :attributes_to_exclude | ||
class SafeCopyAttributesService | ||
def self.run(source_instance:, target_class:, attributes_to_exclude: []) | ||
new(source_instance, target_class, attributes_to_exclude).run | ||
end | ||
|
||
def run(source_instance:, target_class:, embedded_documents: [], attributes_to_exclude: []) | ||
def initialize(source_instance, target_class, attributes_to_exclude = []) | ||
@source_instance = source_instance | ||
@target_class = target_class | ||
@embedded_documents = embedded_documents | ||
@attributes_to_exclude = attributes_to_exclude | ||
end | ||
|
||
source_attributes.except(*unsupported_attribute_keys) | ||
def run | ||
copy_attributes(@source_instance, @target_class) | ||
end | ||
|
||
def source_attributes | ||
attributes = source_instance.is_a?(BSON::Document) ? source_instance : source_instance.attributes | ||
private | ||
|
||
# Recursively copies attributes from the source to match the target class | ||
def copy_attributes(source, target_class) | ||
attributes = extract_attributes(source) | ||
valid_attributes = filter_attributes(attributes, target_class) | ||
embedded_attributes = process_embedded_relations(attributes, target_class) | ||
valid_attributes.merge(embedded_attributes) | ||
end | ||
|
||
attributes.except(*attributes_to_exclude) | ||
# Extracts attributes from the source instance based on its type | ||
def extract_attributes(source) | ||
case source | ||
when Hash, BSON::Document | ||
source.to_h.stringify_keys | ||
when ->(obj) { obj.respond_to?(:attributes) } | ||
source.attributes | ||
else | ||
raise ArgumentError, "Unsupported source_instance type: #{source.class}" | ||
end | ||
end | ||
|
||
def target_fields | ||
# Include both camelCase (DB) and snake_case (model) attribute names: | ||
(target_class.fields.keys + target_class.fields.keys.map(&:underscore)).uniq | ||
# Filters attributes to include only those defined in the target class, excluding specified attributes | ||
def filter_attributes(attributes, target_class) | ||
target_fields = target_class.fields.keys.map(&:to_s) | ||
attributes.slice(*target_fields).except("_id", *@attributes_to_exclude) | ||
end | ||
|
||
# Processes embedded relations defined in the target class | ||
def process_embedded_relations(attributes, target_class) | ||
embedded_attributes = {} | ||
|
||
target_class.embedded_relations.each do |relation_name, relation_metadata| | ||
# Skip if the relation is in the attributes_to_exclude list | ||
next if @attributes_to_exclude.map(&:underscore).include?(relation_name.underscore) | ||
|
||
# Find the corresponding key in attributes (handles snake_case and camelCase) | ||
key = matching_attribute_key(attributes, relation_name) | ||
next unless key | ||
|
||
source_data = attributes[key] | ||
embedded_class = relation_metadata.class_name.constantize | ||
embedded_attributes[key] = process_embedded_data(source_data, embedded_class) | ||
end | ||
|
||
embedded_attributes | ||
end | ||
|
||
# Finds the attribute key in attributes that corresponds to the relation name | ||
def matching_attribute_key(attributes, relation_name) | ||
snake_case_name = relation_name.underscore | ||
camel_case_name = relation_name.camelize(:lower) | ||
|
||
if attributes.key?(snake_case_name) | ||
snake_case_name | ||
elsif attributes.key?(camel_case_name) | ||
camel_case_name | ||
end | ||
end | ||
|
||
def unsupported_attribute_keys | ||
source_attributes.except(*target_fields).excluding(embedded_documents).keys | ||
# Recursively processes embedded data | ||
def process_embedded_data(data, embedded_class) | ||
if data.is_a?(Array) | ||
data.map { |item| copy_attributes(item, embedded_class) } | ||
elsif data.is_a?(Hash) || data.is_a?(BSON::Document) | ||
copy_attributes(data, embedded_class) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,3 +16,4 @@ en: | |
attributes: | ||
contact_address: | ||
blank: "Select an address" | ||
should_be_uk: "Provide a UK contact address" |
Oops, something went wrong.