From 599a5fe3b7f5cdeff99af6dc8d1b9879d86e2b16 Mon Sep 17 00:00:00 2001 From: Tim Connor Date: Mon, 7 Dec 2020 16:48:10 +1300 Subject: [PATCH] Fix lazy loaded nested associations Fixes #129 --- lib/fast_jsonapi/serialization_core.rb | 5 +++++ spec/fixtures/actor.rb | 8 +++++++ spec/fixtures/movie.rb | 7 +++++++ spec/integration/relationships_spec.rb | 29 ++++++++++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/lib/fast_jsonapi/serialization_core.rb b/lib/fast_jsonapi/serialization_core.rb index 4931fa7..42bff29 100644 --- a/lib/fast_jsonapi/serialization_core.rb +++ b/lib/fast_jsonapi/serialization_core.rb @@ -66,6 +66,8 @@ module FastJsonapi end def record_hash(record, fieldset, includes_list, params = {}) + includes_list = parse_includes_list(includes_list) + if cache_store_instance cache_opts = record_cache_options(cache_store_options, fieldset, includes_list, params) record_hash = cache_store_instance.fetch(record, **cache_opts) do @@ -153,6 +155,9 @@ module FastJsonapi # @param includes_list [List] to be parsed # @return [Hash] def parse_includes_list(includes_list) + return {} unless includes_list.present? + return includes_list if includes_list.is_a?(Hash) + includes_list.each_with_object({}) do |include_item, include_sets| include_base, include_remainder = include_item.to_s.split('.', 2) include_sets[include_base.to_sym] ||= Set.new diff --git a/spec/fixtures/actor.rb b/spec/fixtures/actor.rb index f85120a..149cb63 100644 --- a/spec/fixtures/actor.rb +++ b/spec/fixtures/actor.rb @@ -31,6 +31,14 @@ class ActorSerializer < UserSerializer ) do |object| object.movies end + + has_many( + :lazy_played_movies, + serializer: :movie + ) do |object| + object.movies + end + end class CamelCaseActorSerializer diff --git a/spec/fixtures/movie.rb b/spec/fixtures/movie.rb index 3156443..59ae756 100644 --- a/spec/fixtures/movie.rb +++ b/spec/fixtures/movie.rb @@ -72,6 +72,13 @@ class MovieSerializer related: ->(obj) { obj.url(obj) } } ) + has_many( + :lazy_actors, + id_method_name: :uid, + lazy_load_data: true + ) do |object| + object.actors + end has_one( :creator, object_method_name: :owner, diff --git a/spec/integration/relationships_spec.rb b/spec/integration/relationships_spec.rb index f0585a8..c56b943 100644 --- a/spec/integration/relationships_spec.rb +++ b/spec/integration/relationships_spec.rb @@ -141,6 +141,35 @@ RSpec.describe JSONAPI::Serializer do ) end end + + context 'with lazy loading' do + let(:params) do + { include: ['lazy_actors.lazy_played_movies'] } + end + + it do + actors_rel = movie.actors.map { |a| { 'id' => a.uid, 'type' => 'actor' } } + + expect(serialized['data']).to have_relationship('lazy_actors').with_data(actors_rel) + + expect(serialized['included']).to include( + have_type('actor') + .and(have_id(movie.actors[0].uid)) + .and( + have_relationship('lazy_played_movies').with_data( + [{ + 'id' => movie.actors[0].movies[0].id, + 'type' => 'movie' + }] + ) + ) + ) + + expect(serialized['included']).to include( + have_type('movie').and(have_id(movie.actors[0].movies[0].id)) + ) + end + end end end end