From b4395f281b7ad0e11866500acadc5f68676bb576 Mon Sep 17 00:00:00 2001 From: twinturbo Date: Wed, 11 Jul 2012 14:57:32 +0200 Subject: [PATCH] Add basic caching --- lib/active_model/serializer.rb | 56 ++++++++++++++++++-- test/caching_test.rb | 97 ++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 test/caching_test.rb diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 66dbde81..332a7f3e 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -69,7 +69,15 @@ module ActiveModel class_attribute :use_default_render_json self.use_default_render_json = false + class_attribute :cache + class_attribute :perform_caching + class << self + # set peform caching like root + def cache(value = true) + self.perform_caching = value + end + # Define attributes to be used in the serialization. def attributes(*attrs) @@ -266,6 +274,16 @@ module ActiveModel hash[meta_key] = @options[:meta] if @options.has_key?(:meta) end + def to_json(*args) + if perform_caching? + cache.fetch expand_cache_key([self.class.to_s.underscore, object.cache_key, 'to-json']) do + super + end + else + super + end + end + # Returns a json representation of the serializable # object including the root. def as_json(options={}) @@ -284,10 +302,15 @@ module ActiveModel # Returns a hash representation of the serializable # object without the root. def serializable_hash - return nil if @object.nil? - @node = attributes - include_associations! if _embed - @node +<<<<<<< HEAD +======= + if perform_caching? + cache.fetch expand_cache_key([self.class.to_s.underscore, object.cache_key, 'serializable-hash']) do + _serializable_hash + end + else + _serializable_hash + end end def include_associations! @@ -400,6 +423,31 @@ module ActiveModel alias :read_attribute_for_serialization :send + # def _serializable_hash + # instrument(:serialize, :serializer => self.class.name) do + # node = attributes + # instrument :associations do + # include_associations!(node) if _embed + # end + # node + # end + # end + + def _serializable_hash + return nil if @object.nil? + @node = attributes + include_associations! if _embed + @node + end + + def perform_caching? + perform_caching && cache && object.respond_to?(:cache_key) + end + + def expand_cache_key(*args) + ActiveSupport::Cache.expand_cache_key(args) + end + # Use ActiveSupport::Notifications to send events to external systems. # The event name is: name.class_name.serializer def instrument(name, payload = {}, &block) diff --git a/test/caching_test.rb b/test/caching_test.rb new file mode 100644 index 00000000..614c407d --- /dev/null +++ b/test/caching_test.rb @@ -0,0 +1,97 @@ +require "test_helper" + +class CachingTest < ActiveModel::TestCase + class NullStore + def fetch(key) + return store[key] if store[key] + + store[key] = yield + end + + def clear + store.clear + end + + def store + @store ||= {} + end + + def read(key) + store[key] + end + end + + class Programmer + def name + 'Adam' + end + + def skills + %w(ruby) + end + + def cache_key + name + end + + def read_attribute_for_serialization(name) + send name + end + end + + def test_serializers_have_a_cache_store + ActiveModel::Serializer.cache = NullStore.new + + assert ActiveModel::Serializer.cache + end + + def test_serializers_can_enable_caching + serializer = Class.new(ActiveModel::Serializer) do + cache true + end + + assert serializer.perform_caching + end + + def test_serializers_cache_serializable_hash + serializer = Class.new(ActiveModel::Serializer) do + cache true + attributes :name, :skills + + def self.to_s + 'serializer' + end + end + + serializer.cache = NullStore.new + instance = serializer.new Programmer.new + + instance.to_json + + assert_equal({ + :name => 'Adam', + :skills => ['ruby'], + }, serializer.cache.read('serializer/Adam/serializable-hash')) + end + + def test_serializers_cache_to_json + serializer = Class.new(ActiveModel::Serializer) do + cache true + attributes :name, :skills + + def self.to_s + 'serializer' + end + end + + serializer.cache = NullStore.new + instance = serializer.new Programmer.new + + instance.to_json + + assert_equal({ + :name => 'Adam', + :skills => ['ruby'], + }.to_json, serializer.cache.read('serializer/Adam/to-json')) + end +end