Tweaks the serialization behavior so that when a resource is explicitly
set to a resource's field and that resource is subsequently saved, then
if it looks like the set resource was persisted we extract its ID and
send it up to the API.
By slight extension we also throw an `ArgumentError` if it looks like
that set resource was _not_ persisted because if the user set it
explicitly then it was probably not their intention to have it silently
ignored by the library in the event of a problem.
Previously, the value of whatever accessor was missing was left out of
the call to build it. This had the effect of skipping over the
lazily-built predicate method when the missing accessor is for a
boolean.
Of course, I realize this all is a bit contrived as most of the time
folks aren't assigning these values manually to stripe objects. However,
in my testing it caught me by surprised that the behavior is asymmetric
depending on how and when values are assigned.
As such I believe this is a less surprising implementation.
As described in #481, adding a protected field like `legal_entity` as
part of an update API operation can cause some issues like a custom
encoding scheme not being considered and special handling around empty
values being ignored.
As a an easy fix for this, let's disallow access to protected fields in
the same way that we disallow them from being set directly on an
instance of a given model.
Helps address (but is not a complete fix for) #481.
Introduce a `#save_with_parent` flag that allows the default behavior of
never saving API resources nested under a parent to be overridden, a
feature that we so far only know to need for updating a source under a
customer.
I'm not sure exactly what changed here (did we change the `$VERBOSE`
setting?), but I'm not seeing a whole lot of warnings when running the
test suites locally and in CI. For example:
```
Started
........................................./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
............../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
......../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
.../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
........./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
...
..../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
....../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
..../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
......./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
........./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
........../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
................./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
.../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
..../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
....../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
..........
........./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
....../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
......../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
......../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
............./home/travis/build/stripe/stripe-ruby/lib/stripe/stripe_object.rb:35: warning: instance variable @values not initialized
./home/travis/build/stripe/stripe-ruby/lib/stripe/stripe_object.rb:35: warning: instance variable @values not initialized
...................../home/travis/build/stripe/stripe-ruby/lib/stripe/transfer.rb:8: warning: instance variable @api_key not initialized
..............
..
Finished in 0.785621037 seconds.
```
Most of these are due to unused or uninitialized variables. This patch
fixes all warnings by fixing offending code.
Prior to my last major serialization refactor, there was a check in the
code that would remove any subobjects from serialization that were of
their own proper resource type (for example, if a charge contained a
customer, that customer would be removed).
What I didn't realize at the time is that the old serialization code had
a bug/quirk that would allow *certain types* of subobjects that were API
resources to make it through unscathed.
In short, the behavior requirement here is *directly* contradictory.
There was a test in place that would make sure that `customer` was
removed from this hash:
``` ruby
{
:id => 'ch_id',
:object => 'charge',
:customer => {
:object => 'customer',
:id => 'customer_id'
}
}
```
But, as reported in #406, we expect, and indeed need, for `source` (a
card) to make it through to the API in this hash:
``` ruby
{
:id => 'cus_id',
:object => 'customer',
:source => {
:object => 'card',
:id => 'card_id'
}
}
```
My proposal here is to just remove the check on serializing API
resources. The normal code that only sends up keys/hashes that have
changed is still in place, so in the first example, `customer` still
isn't sent unless the user has directly manipulated a field on that
subobject. I propose that in those cases we allow the API itself to
reject the request rather than try to cut it off at the client level.
Unfortunately, there is some possibility that removing those API
resources is important for some reason, but of course there's no
documentation on it beyond the after-the-fact post-justification that I
wrote during my last refactor. I can't think of any reason that it would
be too destructive, but there is some level of risk.
This pull does two major things:
1. Refactors `serialize_params` to be more concise and readable while
still complying to our existing test suite. Unfortunately over time
this method has become a ball of mud that's very difficult to reason
about, as recently evidenced by #384.
2. Moves `serialize_params` from class method to instance method (while
still keeping for old class method for backwards compatibility). This
is to give it a more sane interface.
Hashes are converted to StripeObject when used as params of save.
They need to be converted to hash on serialize.
Signed-off-by: François de Metz <francois@stormz.me>
Signed-off-by: Cyril Duez <cyril@stormz.me>
This is kind of a weird one because it'll only cause a failure when
serializing a subobject or hash of a `StripeObject`, but it's good
practice to initialize instance variables anyway.
Fixes#360.
We attempt to do a special encoding trick when serializing
`additional_owners` under an account: when updating a value, we actually
send the update parameters up as an integer-indexed hash rather than an
array. So instead of this:
field[]=item1&field[]=item2&field[]=item3
We send this:
field[0]=item1&field[1]=item2&field[2]=item3
The trouble is that this had previously been built into the core library
as the default handling for all arrays. Because of this, it was
impossible to resize a non-`additional_owners` array as described in
more detail in #340.
This patch special cases `additional_owners` and brings sane behavior
back to normal arrays along with a test suite so that we try to build
some better guarantees around both the general and non-general cases.
Unfortunately usage of `#update_attributes` had rolled over from a time
where `#update_attributes_with_options` was still in use and `opts` were
being passed in as an optional argument which had the result of further
nesting the hash internally (i.e. `:opts => { :opts => ... } }`).
This patch fixes that problem, adds a regression test to prevent it from
reappearing, and banishes the unused `#update_attributes_with_options`.
Fixes#334.
Adds a special helper to `StripeObject` that helps a developer to
determine whether or not an object is deleted.
As described originally in #257, this is a bit of a special case because
a non-deleted object does not respond with `deleted` as part of its
representation, so while a deleted object would have this accessor
available automatically, non-deleted objects would not. This made use of
the SDK awkward because the presence of the method was not guaranteed.
Fixes#257 (again, heh).
This dials down the safety of `StripeObject`'s `#update_attributes`
method so that it allows properties to be assigned that it doesn't yet
know about. We're doing this for a few reasons:
1. To reflect the current behavior of accessors (i.e. `obj.name = ...`)
through `method_missing`.
2. To allow `#update_attributes` to assign properties on new projects
that don't yet know their schema from an API call.
Fixes#324.
As discussed in #325, this deprecates the public visibility of
`#refresh_from` (by renaming it). It also adds some deprecation
infrastructure to produce warnings when it's used.
Usage on a top-level collection:
```
Stripe::Customer.list.auto_paging_each do |customer|
puts customer
end
```
Usage on a subcollection:
``` ruby
customer.invoices.auto_paging_each do |invoice|
puts invoice
end
```
We've also renamed `#all` to `#list` to prevent confusion ("all" implies
that all resources are being returned, and in Stripe's paginated API
this was not the case). An alias has been provided for backward API
compatibility.
Fixes#167.
Replaces #211 and #248.
As detailed in issue #119, we've somewhat unfortunately been allowing
object attributes to be passed in during a #save because we mix any
arguments directly into the serialized hash (it seems that this was
originally intended to be used more for meta parameters that go to the
request).
As also noted in #119, this use causes problems when certain types of
parameters (like subobjects) are used. We're now left in the somewhat
awkward position of either:
1. Removing this functionality on #save and breaking what may be
behavior that people depend on.
2. Fully support this mass assignment.
This patch takes the second path by extracting a new #update_attributes
method and using it from #save. It's still far from a perfect approach
because keys that have the same name as certain options (e.g. `req_url`)
are not going to work, but it should capture the behavior that most
people want.
Fixes#119.
This patch adds question marks helpers (e.g. #paid?) for any values in a
StripeObject that are a boolean. This is fairly idiomatic Ruby in that
it behaves similarly to other libraries like ActiveRecord.
Note that a caveat here is that nullable booleans will not get a helper
added for them if their current value is null. For this reason, we
should eventually prefer to derive these methods from some sort of
programmatic API manifest.
Replaces #257 and #274.
When constructing an object using .construct_from treat keys that are
strings the same as keys which are symbols by calling Util's
symbolize_names on an input hash. This makes guarantees around
consistency a little better.
Fixes#151.