From 5375e009e28ebf2d6c66891fed9fcb2386180c9f Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Tue, 7 Jun 2016 03:57:24 -0500 Subject: [PATCH] Test caching with fragmented key - on association, fix up assocation logic - on attribute --- lib/active_model/serializer/caching.rb | 20 ++----- .../explicit_serializer_test.rb | 2 +- test/cache_test.rb | 55 ++++++++++++++----- test/fixtures/poro.rb | 11 ++-- 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/lib/active_model/serializer/caching.rb b/lib/active_model/serializer/caching.rb index e7bd6e73..a1692275 100644 --- a/lib/active_model/serializer/caching.rb +++ b/lib/active_model/serializer/caching.rb @@ -70,9 +70,9 @@ module ActiveModel def fragmented_attributes cached = _cache_only ? _cache_only : _attributes - _cache_except - cached = cached.map! {|field| _attributes_keys.fetch(field, field) } + cached = cached.map! { |field| _attributes_keys.fetch(field, field) } non_cached = _attributes - cached - non_cached = non_cached.map! {|field| _attributes_keys.fetch(field, field) } + non_cached = non_cached.map! { |field| _attributes_keys.fetch(field, field) } { cached: cached, non_cached: non_cached @@ -233,28 +233,20 @@ module ActiveModel def fetch_attributes_fragment(adapter_instance) self.class._cache_options ||= {} self.class._cache_options[:key] = self.class._cache_key if self.class._cache_key - options = { include_directive: ActiveModel::Serializer.include_directive_from_options({})} fields = self.class.fragmented_attributes non_cached_fields = fields[:non_cached].dup non_cached_hash = attributes(non_cached_fields, true) - (non_cached_fields - non_cached_hash.keys).each do |missing_field| - # TODO: use _attributes_keys? - # gets any other associations, etc. - non_cached_hash[missing_field] = read_attribute_for_serialization(missing_field) - end + include_directive = JSONAPI::IncludeDirective.new(non_cached_fields - non_cached_hash.keys) + non_cached_hash.merge! resource_relationships({}, { include_directive: include_directive }, adapter_instance) cached_fields = fields[:cached].dup key = cache_key(adapter_instance) cached_hash = self.class.cache_store.fetch(key, self.class._cache_options) do hash = attributes(cached_fields, true) - (cached_fields - hash.keys).each do |missing_field| - # TODO: use _attributes_keys? - # gets any other associations, etc. - hash[missing_field] = read_attribute_for_serialization(missing_field) - end - hash + include_directive = JSONAPI::IncludeDirective.new(cached_fields - hash.keys) + hash.merge! resource_relationships({}, { include_directive: include_directive }, adapter_instance) end # Merge both results diff --git a/test/action_controller/explicit_serializer_test.rb b/test/action_controller/explicit_serializer_test.rb index 8886d07d..a23b6f6b 100644 --- a/test/action_controller/explicit_serializer_test.rb +++ b/test/action_controller/explicit_serializer_test.rb @@ -123,7 +123,7 @@ module ActionController id: 42, lat: '-23.550520', lng: '-46.633309', - place: 'Nowhere' # is a virtual attribute on LocationSerializer + address: 'Nowhere' # is a virtual attribute on LocationSerializer } ] } diff --git a/test/cache_test.rb b/test/cache_test.rb index 5df93432..57312a91 100644 --- a/test/cache_test.rb +++ b/test/cache_test.rb @@ -127,7 +127,7 @@ module ActiveModelSerializers end def test_fragment_cache_definition - assert_equal([:name], @role_serializer.class._cache_only) + assert_equal([:name, :slug], @role_serializer.class._cache_only) assert_equal([:content], @bio_serializer.class._cache_except) end @@ -178,14 +178,14 @@ module ActiveModelSerializers id: @location.id, lat: @location.lat, lng: @location.lng, - place: 'Nowhere' + address: 'Nowhere' } hash = render_object_with_cache(@location) assert_equal(hash, expected_result) key = "#{@location.cache_key}/#{adapter.cache_key}" - assert_equal({ place: 'Nowhere' }, cache_store.fetch(key)) + assert_equal({ address: 'Nowhere' }, cache_store.fetch(key)) end def test_fragment_cache_with_inheritance @@ -434,21 +434,46 @@ module ActiveModelSerializers end def test_fragment_fetch_with_virtual_attributes - @author = Author.new(name: 'Joao M. D. Moura') - @role = Role.new(name: 'Great Author', description: nil) - @role.author = [@author] - @role_serializer = RoleSerializer.new(@role) - adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@role_serializer) - @role_hash = @role_serializer.fetch_attributes_fragment(adapter_instance) - + author = Author.new(name: 'Joao M. D. Moura') + role = Role.new(name: 'Great Author', description: nil) + role.author = [author] + role_serializer = RoleSerializer.new(role) + adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(role_serializer) expected_result = { - id: @role.id, - description: @role.description, - slug: "#{@role.name}-#{@role.id}", - name: @role.name + id: role.id, + description: role.description, + slug: "#{role.name}-#{role.id}", + name: role.name } + cache_store.clear - assert_equal(@role_hash, expected_result) + role_hash = role_serializer.fetch_attributes_fragment(adapter_instance) + assert_equal(role_hash, expected_result) + + role.attributes[:id] = 'this has been updated' + role.name = 'this was cached' + + role_hash = role_serializer.fetch_attributes_fragment(adapter_instance) + assert_equal(expected_result.merge(id: role.id), role_hash) + end + + def test_fragment_fetch_with_except + adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@bio_serializer) + expected_result = { + id: @bio.id, + rating: nil, + content: @bio.content + } + cache_store.clear + + bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance) + assert_equal(expected_result, bio_hash) + + @bio.content = 'this has been updated' + @bio.rating = 'this was cached' + + bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance) + assert_equal(expected_result.merge(content: @bio.content), bio_hash) end def test_fragment_fetch_with_namespaced_object diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index 71be0108..20c961ee 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -136,10 +136,11 @@ AuthorSerializer = Class.new(ActiveModel::Serializer) do end RoleSerializer = Class.new(ActiveModel::Serializer) do - cache only: [:name], skip_digest: true - attributes :id, :name, :description, :slug + cache only: [:name, :slug], skip_digest: true + attributes :id, :name, :description + attribute :friendly_id, key: :slug - def slug + def friendly_id "#{object.name}-#{object.id}" end @@ -153,10 +154,10 @@ LikeSerializer = Class.new(ActiveModel::Serializer) do end LocationSerializer = Class.new(ActiveModel::Serializer) do - cache only: [:place], skip_digest: true + cache only: [:address], skip_digest: true attributes :id, :lat, :lng - belongs_to :place + belongs_to :place, key: :address def place 'Nowhere'