Skip to content
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

StripeObject#method_missing doesn't agree with StripeObject#respond_to_missing? #324

Closed
bloopletech opened this issue Oct 8, 2015 · 4 comments

Comments

@bloopletech
Copy link

Example:

> account = Stripe::Account.new
 => #<Stripe::Account:0x4f9e6c0> JSON: {
}
> account.respond_to?('email=')
 => false
> account.email = '123@example.com'
 => "123@example.com"
> account.email
 => "123@example.com"

The #method_missing implementation on StripeObject allows the user to assign arbitrary key/values into the @values hash. However, #respond_to_missing? only returns true if the method name passed in matches a key that is already in the @values hash.

This has follow on effects which I'm going to write up into a separate issue, but an example of the other issues this introduces is:

> account = Stripe::Account.new
 => #<Stripe::Account:0x4f8f6e8> JSON: {
}
> account.update_attributes({ email: '123@example.com' })
ArgumentError: email is not an attribute that can be assigned on this object
> account.email = '123@example.com'
 => "123@example.com"
> account.email
 => "123@example.com"

Because #update_attributes_with_options calls #respond_to? to check whether to allow the assignment, it will fail until something either adds the key to @values, or adds the accessor method to the object.

@bloopletech bloopletech changed the title StripeObject#method_missing doesn' StripeObject#method_missing doesn't agree with StripeObject#respond_to_missing? Oct 8, 2015
@brandur
Copy link
Contributor

brandur commented Oct 8, 2015

Thanks for writing in @bloopletech!

So although a discrepancy around #respond_to? helps cause this problem, I think the actual lapse in functionality that we're concerned with is that #update_attributes is more heavy-handed about what it allows to be set than direct assignment (i..e account.email = ...).

The most obvious thing to do here is to loosen its constraints so that they fall in-line with direct assignment. In a way I hate to do this though, because we'd be giving up one of the very, very few places in this gem where we've managed to put any kind of safety in. Another possibility is that we could add #update_attributes_unsafe which would set anything but strongly imply that the operation may produce unexpected results, and then aim to deprecate that version of the method once we have the ability to do so (i.e. a schema).

I'm probably going to lean toward the latter solution unless some other ideas are presented here. /cc @kyleconroy

@kyleconroy
Copy link
Contributor

Hmm, I think update_attributes should probably have the same affect as direct assignment. In the future, we can then make assignment and attribute setting both much safer.

brandur pushed a commit that referenced this issue Oct 8, 2015
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.
@brandur
Copy link
Contributor

brandur commented Oct 8, 2015

Hmm, I think update_attributes should probably have the same affect as direct assignment. In the future, we can then make assignment and attribute setting both much safer.

Yeah, good call. Dialed down safety to fix this issue in #329.

@bloopletech
Copy link
Author

Awesome! Thanks for looking at this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants