Since #433, saving API resources nested under other API resources has
not been the default. Instead, any instances where this should occur
have been special cased with specific method implementations that would
set the `#save_with_parent` flag when a field is written.
This ended up causing some problems because as seen in #457, because
places that we need to do this aren't well vetted, some were forgotten.
This makes implementation of new fields that need this behavior simpler
by implementing a `.save_nested_resource` metraprogramming method on the
`APIResource` class. This can be called as necessary by any concrete API
resource implementations.
We replace existing implementatinos and also add one to `Subscription`,
which had previously been suffering from a similar problem where its
`#source` had not received a special case.
Add deprecated `#bank_account=` to maintain backwards compatibility.
This would have been broken by #433, so this change keeps the
functionality alive in case someone has not upgraded since.
In #433, we built a framework under which subresources are usually not
persisted, but in certain cases they can be. At the time,
`Customer#source` was the only field that I knew about that had to be
flagged into it.
Issue #456 has raised that we also be doing `Account#external_account`.
This patch adds support for that.
Fixes#456.
This produces an error when we detect an "array of maps" that cannot be
encoded with `application/x-www-form-urlencoded`; that is to say, one
that does not have each hash starting with a consistent key that will
allow a Rack-compliant server to recognize boundaries.
So for example, this is fine:
```
items: [
{ :type => 'sku', :parent => 'sku_94ZYSC0wppRTbk' },
{ :type => 'discount', :amount => -10000, :currency => 'cad', :description => 'potato' }
],
```
But this is _not_ okay:
```
items: [
{ :type => 'sku', :parent => 'sku_94ZYSC0wppRTbk' },
{ :amount => -10000, :currency => 'cad', :description => 'potato', :type => 'discount' }
],
```
(`type` should be moved to the beginning of the array.)
The purpose of this change is to give users better feedback when they
run into an encoding problem like this one. Currently, they just get
something confusing from the server, and someone on support usually
needs to examine a request log to figure out what happened.
CI will fail until the changes in #453 are brought in.
Alphabetizing maps being encoded by key can cause problems because the
server side Rack relies on the fact that that a new array item will
start with a repeated key.
For example, given this encoding:
```
items: [
{ :type => 'sku', :parent => 'sku_94ZYSC0wppRTbk' },
{ :type => 'discount', :amount => -10000, :currency => 'cad', :description => 'potato' }
],
```
We need to have `type` appear first so that an array boundary is
recognized. So the encoded form should take:
```
items[][type]=sku&items[][parent]=...&items[][type]=discount&items[][amount]=...
```
But currently `type` gets sorted to the back, so we get something more
like:
```
items[][parent]=...&items[][type]=...&items[][amount]=...&items[][currency]=...&items[][description]=...&items[][type]=potato
```
Which the server will receive as this:
```
items: [
{ :type => 'sku', :parent => 'sku_94ZYSC0wppRTbk', :amount => -10000, :currency => 'cad', :description => 'potato' }
{ :type => 'discount' }
],
```
Here we remove the alphabetization to fix the problem and correct a bad
test.
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.
* Rename the `Update` operation to `Save`
* Add the `update` class method to all saveable resources
* Add tests for update method
* Add tests for plans, invoice items, and application fees
* allow subs to be retrieved & created with new v1/subs API endpoint
* edit tests to check for url
* fix customer subscription URLs to go through v1/customers
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.