Skip to content

Commit 12cd190

Browse files
committed
Merge pull request #1402 from beauby/extract-caching
Extract caching into its own module
2 parents bb67735 + fd06a8a commit 12cd190

File tree

2 files changed

+109
-89
lines changed

2 files changed

+109
-89
lines changed

lib/active_model/serializer.rb

Lines changed: 9 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require 'active_model/serializer/include_tree'
55
require 'active_model/serializer/associations'
66
require 'active_model/serializer/attributes'
7+
require 'active_model/serializer/caching'
78
require 'active_model/serializer/configuration'
89
require 'active_model/serializer/fieldset'
910
require 'active_model/serializer/lint'
@@ -15,63 +16,19 @@ class Serializer
1516
include Configuration
1617
include Associations
1718
include Attributes
19+
include Caching
1820
require 'active_model/serializer/adapter'
1921

20-
# Matches
21-
# "c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb:1:in `<top (required)>'"
22-
# AND
23-
# "/c/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb:1:in `<top (required)>'"
24-
# AS
25-
# c/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb
26-
CALLER_FILE = /
27-
\A # start of string
28-
.+ # file path (one or more characters)
29-
(?= # stop previous match when
30-
:\d+ # a colon is followed by one or more digits
31-
:in # followed by a colon followed by in
32-
)
33-
/x
34-
35-
# Hashes contents of file for +_cache_digest+
36-
def self.digest_caller_file(caller_line)
37-
serializer_file_path = caller_line[CALLER_FILE]
38-
serializer_file_contents = IO.read(serializer_file_path)
39-
Digest::MD5.hexdigest(serializer_file_contents)
40-
rescue TypeError, Errno::ENOENT
41-
warn <<-EOF.strip_heredoc
42-
Cannot digest non-existent file: '#{caller_line}'.
43-
Please set `::_cache_digest` of the serializer
44-
if you'd like to cache it.
45-
EOF
46-
''.freeze
47-
end
48-
4922
with_options instance_writer: false, instance_reader: false do |serializer|
5023
serializer.class_attribute :_type, instance_reader: true
51-
serializer.class_attribute :_links # @api private : links definitions, @see Serializer#link
24+
serializer.class_attribute :_links # @api private : links definitions, @see Serializer#link
5225
self._links ||= {}
53-
serializer.class_attribute :_cache # @api private : the cache object
54-
serializer.class_attribute :_fragmented # @api private : @see ::fragmented
55-
serializer.class_attribute :_cache_key # @api private : when present, is first item in cache_key
56-
serializer.class_attribute :_cache_only # @api private : when fragment caching, whitelists cached_attributes. Cannot combine with except
57-
serializer.class_attribute :_cache_except # @api private : when fragment caching, blacklists cached_attributes. Cannot combine with only
58-
serializer.class_attribute :_cache_options # @api private : used by CachedSerializer, passed to _cache.fetch
59-
# _cache_options include:
60-
# expires_in
61-
# compress
62-
# force
63-
# race_condition_ttl
64-
# Passed to ::_cache as
65-
# serializer._cache.fetch(cache_key, @klass._cache_options)
66-
serializer.class_attribute :_cache_digest # @api private : Generated
6726
end
6827

6928
# Serializers inherit _attribute_mappings, _reflections, and _links.
7029
# Generates a unique digest for each serializer at load.
7130
def self.inherited(base)
72-
caller_line = caller.first
7331
base._links = _links.dup
74-
base._cache_digest = digest_caller_file(caller_line)
7532
super
7633
end
7734

@@ -86,43 +43,6 @@ def self.link(name, value = nil, &block)
8643
_links[name] = block || value
8744
end
8845

89-
# @api private
90-
# Used by FragmentCache on the CachedSerializer
91-
# to call attribute methods on the fragmented cached serializer.
92-
def self.fragmented(serializer)
93-
self._fragmented = serializer
94-
end
95-
96-
# Enables a serializer to be automatically cached
97-
#
98-
# Sets +::_cache+ object to <tt>ActionController::Base.cache_store</tt>
99-
# when Rails.configuration.action_controller.perform_caching
100-
#
101-
# @params options [Hash] with valid keys:
102-
# key : @see ::_cache_key
103-
# only : @see ::_cache_only
104-
# except : @see ::_cache_except
105-
# skip_digest : does not include digest in cache_key
106-
# all else : @see ::_cache_options
107-
#
108-
# @example
109-
# class PostSerializer < ActiveModel::Serializer
110-
# cache key: 'post', expires_in: 3.hours
111-
# attributes :title, :body
112-
#
113-
# has_many :comments
114-
# end
115-
#
116-
# @todo require less code comments. See
117-
# https://github.com/rails-api/active_model_serializers/pull/1249#issuecomment-146567837
118-
def self.cache(options = {})
119-
self._cache = ActiveModelSerializers.config.cache_store if ActiveModelSerializers.config.perform_caching
120-
self._cache_key = options.delete(:key)
121-
self._cache_only = options.delete(:only)
122-
self._cache_except = options.delete(:except)
123-
self._cache_options = (options.empty?) ? nil : options
124-
end
125-
12646
# @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
12747
# @return [ActiveModel::Serializer]
12848
# Preferentially returns
@@ -145,12 +65,6 @@ def self.adapter
14565
ActiveModel::Serializer::Adapter.lookup(config.adapter)
14666
end
14767

148-
# Used to cache serializer name => serializer class
149-
# when looked up by Serializer.get_serializer_for.
150-
def self.serializers_cache
151-
@serializers_cache ||= ThreadSafe::Cache.new
152-
end
153-
15468
# @api private
15569
def self.serializer_lookup_chain_for(klass)
15670
chain = []
@@ -165,6 +79,12 @@ def self.serializer_lookup_chain_for(klass)
16579
chain
16680
end
16781

82+
# Used to cache serializer name => serializer class
83+
# when looked up by Serializer.get_serializer_for.
84+
def self.serializers_cache
85+
@serializers_cache ||= ThreadSafe::Cache.new
86+
end
87+
16888
# @api private
16989
# Find a serializer from a class and caches the lookup.
17090
# Preferentially retuns:
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
module ActiveModel
2+
class Serializer
3+
module Caching
4+
extend ActiveSupport::Concern
5+
6+
included do
7+
with_options instance_writer: false, instance_reader: false do |serializer|
8+
serializer.class_attribute :_cache # @api private : the cache object
9+
serializer.class_attribute :_fragmented # @api private : @see ::fragmented
10+
serializer.class_attribute :_cache_key # @api private : when present, is first item in cache_key
11+
serializer.class_attribute :_cache_only # @api private : when fragment caching, whitelists cached_attributes. Cannot combine with except
12+
serializer.class_attribute :_cache_except # @api private : when fragment caching, blacklists cached_attributes. Cannot combine with only
13+
serializer.class_attribute :_cache_options # @api private : used by CachedSerializer, passed to _cache.fetch
14+
# _cache_options include:
15+
# expires_in
16+
# compress
17+
# force
18+
# race_condition_ttl
19+
# Passed to ::_cache as
20+
# serializer._cache.fetch(cache_key, @klass._cache_options)
21+
serializer.class_attribute :_cache_digest # @api private : Generated
22+
end
23+
end
24+
25+
# Matches
26+
# "c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb:1:in `<top (required)>'"
27+
# AND
28+
# "/c/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb:1:in `<top (required)>'"
29+
# AS
30+
# c/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb
31+
CALLER_FILE = /
32+
\A # start of string
33+
.+ # file path (one or more characters)
34+
(?= # stop previous match when
35+
:\d+ # a colon is followed by one or more digits
36+
:in # followed by a colon followed by in
37+
)
38+
/x
39+
40+
module ClassMethods
41+
def inherited(base)
42+
super
43+
caller_line = caller[1]
44+
base._cache_digest = digest_caller_file(caller_line)
45+
end
46+
47+
# Hashes contents of file for +_cache_digest+
48+
def digest_caller_file(caller_line)
49+
serializer_file_path = caller_line[CALLER_FILE]
50+
serializer_file_contents = IO.read(serializer_file_path)
51+
Digest::MD5.hexdigest(serializer_file_contents)
52+
rescue TypeError, Errno::ENOENT
53+
warn <<-EOF.strip_heredoc
54+
Cannot digest non-existent file: '#{caller_line}'.
55+
Please set `::_cache_digest` of the serializer
56+
if you'd like to cache it.
57+
EOF
58+
''.freeze
59+
end
60+
61+
# @api private
62+
# Used by FragmentCache on the CachedSerializer
63+
# to call attribute methods on the fragmented cached serializer.
64+
def fragmented(serializer)
65+
self._fragmented = serializer
66+
end
67+
68+
# Enables a serializer to be automatically cached
69+
#
70+
# Sets +::_cache+ object to <tt>ActionController::Base.cache_store</tt>
71+
# when Rails.configuration.action_controller.perform_caching
72+
#
73+
# @params options [Hash] with valid keys:
74+
# key : @see ::_cache_key
75+
# only : @see ::_cache_only
76+
# except : @see ::_cache_except
77+
# skip_digest : does not include digest in cache_key
78+
# all else : @see ::_cache_options
79+
#
80+
# @example
81+
# class PostSerializer < ActiveModel::Serializer
82+
# cache key: 'post', expires_in: 3.hours
83+
# attributes :title, :body
84+
#
85+
# has_many :comments
86+
# end
87+
#
88+
# @todo require less code comments. See
89+
# https://github.com/rails-api/active_model_serializers/pull/1249#issuecomment-146567837
90+
def cache(options = {})
91+
self._cache = ActiveModelSerializers.config.cache_store if ActiveModelSerializers.config.perform_caching
92+
self._cache_key = options.delete(:key)
93+
self._cache_only = options.delete(:only)
94+
self._cache_except = options.delete(:except)
95+
self._cache_options = (options.empty?) ? nil : options
96+
end
97+
end
98+
end
99+
end
100+
end

0 commit comments

Comments
 (0)