solnic / virtus

[DISCONTINUED ] Attributes on Steroids for Plain Old Ruby Objects
MIT License
3.77k stars 228 forks source link

Distinguishing between nil and undefined attributes #288

Open sqrrrl opened 9 years ago

sqrrrl commented 9 years ago

Thoughts on adding an option to completely disable a default value for an attribute? The particular use case is I need to distinguish between an attribute that has an explicitly set nil value vs. an implied nil by virtue of not being set.

using lazy_default + checking attribute.defined? mostly accomplishes this, but suffers from the undesirable behavior where the reader method will call set_default_value if the instance variable is undefined.

Reasonable to add an option along the lines of :lazy_default (maybe :skip_default) that is stricter and allows an attribute to remain undefined until explicitly set? LMK and I'll submit a PR.

solnic commented 9 years ago

So...you need to know whether nil was passed in or it was set by virtus? Can you provide me with more context? I'm not exactly sure if I want to see even more options in virtus. Frankly I'm planning to simplify virtus for its 2.0 release.

sqrrrl commented 9 years ago

It's for an API client where the underlying rest API supports partial requests (retrieve/set just a subset of properties) and treats unspecified attributes differently than attributes with nil values. Unspecified means don't change the value. An explicit nil means delete/clear the previous value.

The challenge is in serializing the objects to JSON. A nil value is ambiguous. It could be nil because it was never initialized or nil because the developer set the value to nil.

The more generalized version of this is dirty tracking -- being able to enumerate which attributes have been modified since the object was initialized.

ghost commented 9 years ago

did you find a solution? I'm stuck at the same problem and would like to solve it in a general way

sqrrrl commented 9 years ago

Sort of. So long as there are no defaults specified, it's easy enough to check by calling instance_variable_defined? to see if it has been set or not. For my case I can live without defaults. I ended up not using Virtus, but using Representable for the serialization which has some nice options for adding conditions for checking whether or not to serialize a property.