-
Notifications
You must be signed in to change notification settings - Fork 15
[WIP] Ensure references_many no nil value #322
base: master
Are you sure you want to change the base?
Conversation
| @@ -34,6 +34,8 @@ def initialize(args = {}) | |||
| end | |||
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 took 2 hours to check files and write the fix. I didn't check the whole code base. It's possible that I missed some things here. I didn't want to take too much time on this part since I have other tasks to do in this sprint.
Waiting for your review 😄
619320b to
5196609
Compare
|
|
||
| def ensure_references_many_value_presence(args) | ||
| if references_many? && args.fetch(:value).nil? | ||
| args[:value] = [] | ||
| end | ||
| end |
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.
Basically, when an array is not received in the answer (in my case it's amazon business api), references_many is nil. Its value is nil too. I ensure here that if we meet this specific case, we set an empty array instead [].
Why here? Because after, comes the .set_attribute(key, value) and it can't be nil.
I checked files and methods before arriving here. I followed manually the path taken by the code execution. I think that this file is the best place to check value's presence. Other files are even more generic and not appropriate imo.
|
Hey @jkeuleya. Thx for working on this. I'm afraid that this PR is trying to fix it on a wrong layer. Lets try something else here. From what I tracked down is that during deserialization we get the value from hash and then we
from there we exit early in
So the ledger_sync/lib/ledger_sync/serialization/type/deserializer_references_many_type.rb Line 14 in bc868e9
As this is specific just for this type, that feels like its the right place to handle it. Lets remove the exit for Let me know if this approach can work and resolves the issue. |
|
@jkeuleya can you also write a test for this so we ensure we are capturing the expected behavior? That would help me know what you're ultimately trying to achieve. If I am understanding correctly, I'm concerned that this change would be converting It may be easiest to just have a mock of the Amazon Business API response that is failing to create a feature test. |
|
Thank you everyone for your time. I updated the description with an example. EDIT:Classes + spec ready to review. The current PR should help to locate and understand the issue |
e2eee05 to
1074c00
Compare
1074c00 to
15b7e9e
Compare
|
|
||
| class AcceptanceArtifact < LedgerSync::Resource | ||
| attribute :identifier, type: LedgerSync::Type::String | ||
| references_many :packages, to: Package |
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.
What if we add a param called default to references_many so that you could do default: []? I worry that your implementation here is going to be a breaking change. Unless I am missing something, I believe one could argue either way that an API not returning a parameter should result in an empty list or nil. So I think we should make it configurable to make this change backwards compatible.
@jozefvaclavik do you agree?
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.
It's exactly what I searched at the beginning, a default. It was the easy solution but it doesn't exist yet. So yes, it could've been a solution.
For my first implementation, yes, it was a naive approach, I didn't take time to check the whole code base. My goal was to even avoid default param and just do a presence check.
But still, need to think about the implementation of a default while not creating a breaking change.. 🤔
| resource = args.fetch(:resource) | ||
|
|
||
| return if value.nil? | ||
| return [] if value.nil? |
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 this proposition (thanks @jozefvaclavik for your time and your research), we're being more precise/meticulous.
We're working directly on the references_many file.
Nonetheless, we also touched the value_mixin file (see below) which could lead to edge cases since it's a transversal file. I cannot guarantee here. I did ofc several tests with several values and types. I put some breaking points in the code execution trying to understand and check. But still.
| # Do not override this method. Override private method cast_value | ||
| def cast(args = {}) | ||
| assert_valid(args) | ||
| return nil if args.fetch(:value).nil? |
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.
We remove here this responsibility to cast method.
98f319e to
abfb85b
Compare
Issue:
When we have a deserializer with a
references_manyinside and that we don't receive this value in the response of the API call, it crashes.What we want:
When we have a deserializer with a
references_manyinside and that we don't receive this value in the response of the API call, it should just ignore it and continue reading next attributes as it works forreferences_oneandattribute.What's happening concretely in the code:
While deserializing, while arriving on a non existing
reference_manyin the response, we.assign_attributethereference_manywith anilvalue. This causes the crash (lib/ledger_sync/deserializer.rb:44).What's the plan:
Maybe try to set the value to
[](empty array) when the reference is not present in the response.Example:
When I receive the answer from my API call on AmazonBusinessAPI, sometimes, it doesn't have the "packages"
keywith an array asvalue, like that:In the first case, everything works fine. In the second case, the gem searches for
packages, doesn't find it and crashes.