-
Notifications
You must be signed in to change notification settings - Fork 86
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
🐛 Fix fetch
to handle nil
values
#128
Conversation
Another option if we want to preserve backwards-compatibility is to call Example: # Returns an Object, similar to Hash#fetch, except it doesn't raise a KeyError
#
# @param attr_name [String, Symbol]
#
# @return Object
def fetch(attr_name)
attributes.fetch(attr_name.to_s)
rescue KeyError
nil
end |
Cc @DmitryTsepelev not sure who else to tag here 🙏🏽 |
Hi @danielvdao! As far as I remember, @raphox wanted to mimic ActiveModel::AttributeSet, which has the same API with Because of that, I love the idea of keeping the method, but changing it to be safe. def fetch(attr_name)
if attributes.key?(attr_name)
attributes[attr_name]
elsif we_have_attribute_defined?(attr_name) # do not remember the exact way to check that
nil
else
raise KeyError # sounds logical, right?
end
end WDYT? |
Yeah, I agree. I thought about it more myself and making the API safer sounds like the correct thing to do. Also won't break any users today 🙏🏽 Let me give that a shot since I'm not too familiar with the inner API. |
fetch
to attributes
fetch
to handle nil
values
@DmitryTsepelev this seems to be breaking out internal repo, let me see if I can investigate deeper.. Ah I think this is going to be a bit more tricky, because users can define class Bar
include StoreModel::Model
attribute :foo
def foo
super || :fallback
end It seems like the default handling or One option is to do |
What if we do something like this: def fetch(attr_name)
stringified_key = attr_name.to_s
if attributes.key?(stringified_key)
attributes.fetch(stringified_key)
elsif attribute_names.include?(stringified_key) && responds_to?(stringified_key)
public_send(stringified_key)
else
message = attr_name.is_a?(Symbol) ? "key not found: :#{attr_name}" : "key not found: #{attr_name}"
raise KeyError, message
end
end Along with fetching value from attributes, it covers the scenario when attribute is defined, value is not set, but method exists. Otherwise — we raise an error. WDYT? |
That might work! I'll give it a shot. The only concern I have would be if we have a method's Will be a bit slow as it's a holiday for me today, but should be able to try in the next day or so. |
I think there was a few interesting discoveries.
That said, I'm still trying to see if there could be any issue when using |
@DmitryTsepelev when you get a chance, would be great to see if tests work 🙏🏽 I ran them locally, and the few that are failing match with |
Hey @DmitryTsepelev just checking in here! Any updates? Would love to know if I can address any comments or thoughts you may have as well. |
Hey @DmitryTsepelev, apologies for pinging you again. Would love to hear your thoughts on whether or not this is a viable solution. Please let me know, thank you! |
@DmitryTsepelev I saw your GitHub status saying you were slow to respond to issues, is there anyone else I can ask about this? Happy to wait to, but unfortunately there's been no guidance 😔 I understand maintaining open source gems is a lot of work and it is much appreciated! |
Shoot, I somehow managed to miss notifications 😞Lookin |
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.
LGTM!
Context
When relying on delegation of
fetch
toattributes
there are some issues that can cause unexpected / mis-matched behavior due to the underlying keys in theattributes
hash.For example, when we have an object that looks like the following, we'll get different behavior due to
fetch
's exception handling.See d8c468e which shows the passing behavior, and b651dbb which shows the failing behavior.
We discovered this in our usage of a gem called grape-entity. At a high-level the gem will do a large amount of delegation, but do some duck-typing here to see if the object
respond_to?(:fetch, true)
. Whereas before it would just callsend
on the underlying object.I feel like we should remove
fetch
from the public api, as it's not promising 1:1 behavior similar to the dot access method. I also realize it's a breaking change for any users who are using the method today, but if I recall it's only been introduced for 2 weeks, so the sooner the better 🤔Also want to say that we really love this gem, as it's made managing our JSON backed columns so much easier 💚
Issue: #129
Edit
After some thought, we've decided to make the API safer instead, allowing it to handle
nil
keys!