-
Notifications
You must be signed in to change notification settings - Fork 474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds attributes comparator and test case #1282
Conversation
def build_required_attributes(http_method:) | ||
required_attributes = {} | ||
|
||
primary_key_value = send(self.class.primary_key) | ||
unless primary_key_value.nil? | ||
required_attributes[self.class.primary_key] = primary_key_value | ||
end | ||
|
||
diff | ||
path_ids = deduce_path_ids(http_method) | ||
path_ids&.each do |path_id| | ||
path_id_value = send(path_id) | ||
required_attributes[path_id.to_s] = path_id_value unless path_id_value.nil? | ||
end | ||
|
||
required_attributes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this makes the assumption that the primary key and anything required path params might also be required in the body payload
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a reasonable assumption to me.
Checking against the 2024-01 Open API spec files all the put/patch operations list their url params as required param in the body payload
|
if has_numbered_key && ref_value.is_a?(Array) | ||
new_hash[key] = ref_value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
array diff will have the following format
original = { "a" => [] }
updated = { "a" => ["foo"] }
diff = { "a" => { 0 => "foo" } }
However, we don't want to submit the diff values, we want to submit the array so these 2 lines just take the updated value
has_numbered_key = true # because of `0` key
ref_value = ["foo"] # which is_a Array
resulting_hash = { "a" => ["foo"] }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't dig deeper into this because when assigning a resource's array, we either pass in a completely new array, adding to it, modify an existing item in the array or removing an existing item. Then it's better to just use the entire updated array to send to Shopify.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed!
else | ||
new_value = build_update_value(value, path: current_path, reference_values: reference_values) | ||
|
||
new_hash[key] = new_value unless new_value.empty? && !ref_value.empty? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is for cases where an object is explicitly emptied. For example
draft_order = ShopifyAPI::DraftOrder.find(session: @test_session, id: 1143974756657)
draft_order.shipping_address = {}
draft_order.save!
if there was a shipping address in the draft order, this should remove that shipping address from the draft order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in an opposite case, where we only update the address partially but accidentally use the same value for the same attribute, this helps clear out the entire diff because there's nothing to update. It's an edge case. For example
original = {
shipping_address: {
address1: "foo",
address2: "bar"
}
}
updated = {
shipping_address: {
address2: "bar"
}
}
diff = {
shipping_address: {
address1: HashDiff::NO_VALUE # hash_diff thinks we want to remove `address1`
} # address2 doesn't show up because it's not different
}
update_value = {} # should be nothing to update
def build_required_attributes(http_method:) | ||
required_attributes = {} | ||
|
||
primary_key_value = send(self.class.primary_key) | ||
unless primary_key_value.nil? | ||
required_attributes[self.class.primary_key] = primary_key_value | ||
end | ||
|
||
diff | ||
path_ids = deduce_path_ids(http_method) | ||
path_ids&.each do |path_id| | ||
path_id_value = send(path_id) | ||
required_attributes[path_id.to_s] = path_id_value unless path_id_value.nil? | ||
end | ||
|
||
required_attributes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a reasonable assumption to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for tackling this bug! The community will appreciate this fix! 🎉
I was thinking we could add a bit of explicit information into the docs on the usage of REST resources about this.
Explaining that only changed attributes + required URL params are sent when saving.
We could add a information about explicitly setting to null values.
This could help devs debug in the future if there are some cases this solution doesn't cover perfectly.
Co-authored-by: Paulo Margarido <[email protected]>
Description
Fixes #1203
Fixes #1164
How has this been tested?
Checklist: