Expected Behavior
A single Object passed into a serializer should use hash_for_one_record
Actual Behavior
A single Object of type Stripe::PaymentIntent is using hash_for_collection instead
Steps to Reproduce the Problem
- get a single object of type
Stripe::PaymentIntent, which responds to each, but not size or each_pair
- try to serialize it - it will break with fast_jsonapi version >= 1.7.2
- observe breakage, although resource responds to
:id
Specifications
- Version: >= 1.7.2
- Ruby version: 3.2.2
Observations
> resource.class
=> Stripe::PaymentIntent
> resource.respond_to?(:id)
=> true
> resource.respond_to?(:size)
=> false
> resource.respond_to?(:each)
=> true
> resource.respond_to?(:each_pair)
=> false
> resource.id
=> "pi_3xxxxxxxxxxxxxxxxxxxxxxW"
Yes, it is odd that this Stripe object responds to :each for a single object, but shouldn't a response to :id be a stronger indicator that this is not a collection? 🤔
> x = Stripe::PaymentIntent.new
=> #<Stripe::PaymentIntent:0x2feb8> JSON: {
}
> x.respond_to?(:each)
=> true
🤷
Root-Cause
This Change from April 11, 2020
from this PR
changed the behavior how #is_collection? determines if a resource is a collection.
Suggested Fix:
in is_collection? it might be more reliable to first check if the resource responds to :id. If so, it is a single resource, otherwise test for responds to :each, :each_pair, or :size
e.g.: instead of doing this:
def is_collection?(resource, force_is_collection = nil)
return force_is_collection unless force_is_collection.nil?
resource.respond_to?(:each) && !resource.respond_to?(:each_pair)
end
Could we do this?
def is_collection?(resource, force_is_collection = nil)
return force_is_collection unless force_is_collection.nil?
# shouldn't this be a good indicator of a single record?
return false if resource.respond_to?(:id)
# otherwise let's guess
resource.respond_to?(:each) && !resource.respond_to?(:each_pair)
end
Expected Behavior
A single Object passed into a serializer should use
hash_for_one_recordActual Behavior
A single Object of type
Stripe::PaymentIntentis usinghash_for_collectioninsteadSteps to Reproduce the Problem
Stripe::PaymentIntent, which responds toeach, but notsizeoreach_pair:idSpecifications
Observations
Yes, it is odd that this Stripe object responds to
:eachfor a single object, but shouldn't a response to:idbe a stronger indicator that this is not a collection? 🤔🤷
Root-Cause
This Change from April 11, 2020
from this PR
changed the behavior how
#is_collection?determines if a resource is a collection.Suggested Fix:
in
is_collection?it might be more reliable to first check if the resource responds to:id. If so, it is a single resource, otherwise test for responds to:each,:each_pair, or:sizee.g.: instead of doing this:
Could we do this?