@@ -31,6 +31,8 @@ def initialize(primary_resource_klass, options = {})
3131
3232 # Converts a single resource, or an array of resources to a hash, conforming to the JSONAPI structure
3333 def serialize_to_hash ( source )
34+ @top_level_sources = Set . new ( [ source ] . flatten . compact . map { |s | top_level_source_key ( s ) } )
35+
3436 is_resource_collection = source . respond_to? ( :to_ary )
3537
3638 @included_objects = { }
@@ -174,6 +176,14 @@ def custom_links_hash(source)
174176 ( custom_links . is_a? ( Hash ) && custom_links ) || { }
175177 end
176178
179+ def top_level_source_key ( source )
180+ "#{ source . class } _#{ source . id } "
181+ end
182+
183+ def self_referential_and_already_in_source ( resource )
184+ resource && @top_level_sources . include? ( top_level_source_key ( resource ) )
185+ end
186+
177187 def relationships_hash ( source , include_directives )
178188 relationships = source . class . _relationships
179189 requested = requested_fields ( source . class )
@@ -192,39 +202,24 @@ def relationships_hash(source, include_directives)
192202
193203 include_linkage = ia && ia [ :include ]
194204 include_linked_children = ia && !ia [ :include_related ] . empty?
205+ resources = ( include_linkage || include_linked_children ) && [ source . public_send ( name ) ] . flatten . compact
195206
196207 if field_set . include? ( name )
197208 hash [ format_key ( name ) ] = link_object ( source , relationship , include_linkage )
198209 end
199210
200- type = relationship . type
201-
202211 # If the object has been serialized once it will be in the related objects list,
203212 # but it's possible all children won't have been captured. So we must still go
204213 # through the relationships.
205214 if include_linkage || include_linked_children
206- if relationship . is_a? ( JSONAPI ::Relationship ::ToOne )
207- resource = source . public_send ( name )
208- if resource
209- id = resource . id
210- type = relationship . type_for_source ( source )
211- relationships_only = already_serialized? ( type , id )
212- if include_linkage && !relationships_only
213- add_included_object ( id , object_hash ( resource , ia ) )
214- elsif include_linked_children || relationships_only
215- relationships_hash ( resource , ia )
216- end
217- end
218- elsif relationship . is_a? ( JSONAPI ::Relationship ::ToMany )
219- resources = source . public_send ( name )
220- resources . each do |resource |
221- id = resource . id
222- relationships_only = already_serialized? ( type , id )
223- if include_linkage && !relationships_only
224- add_included_object ( id , object_hash ( resource , ia ) )
225- elsif include_linked_children || relationships_only
226- relationships_hash ( resource , ia )
227- end
215+ resources . each do |resource |
216+ next if self_referential_and_already_in_source ( resource )
217+ id = resource . id
218+ relationships_only = already_serialized? ( relationship . type , id )
219+ if include_linkage && !relationships_only
220+ add_included_object ( id , object_hash ( resource , ia ) )
221+ elsif include_linked_children || relationships_only
222+ relationships_hash ( resource , ia )
228223 end
229224 end
230225 end
0 commit comments