Skip to content

Commit efb0905

Browse files
author
Yohan Robert
committed
Refactor fragment cache methods
Removed extra calls to constantize and DRY'd the code.
1 parent f8d2aab commit efb0905

File tree

2 files changed

+49
-43
lines changed

2 files changed

+49
-43
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Features:
2121
- [#1340](https://github.com/rails-api/active_model_serializers/pull/1340) Add support for resource-level meta. (@beauby)
2222

2323
Fixes:
24-
- [#1516](https://github.com/rails-api/active_model_serializers/pull/1501) No longer return a nil href when only
24+
- [#1516](https://github.com/rails-api/active_model_serializers/pull/1516) No longer return a nil href when only
2525
adding meta to a relationship link. (@groyoh)
2626
- [#1458](https://github.com/rails-api/active_model_serializers/pull/1458) Preserve the serializer
2727
type when fragment caching. (@bdmac)
@@ -31,6 +31,7 @@ Fixes:
3131
- [#1488](https://github.com/rails-api/active_model_serializers/pull/1488) Require ActiveSupport's string inflections (@nate00)
3232

3333
Misc:
34+
- [#1527](https://github.com/rails-api/active_model_serializers/pull/1527) Refactor fragment cache class. (@groyoh)
3435
- [#1560](https://github.com/rails-api/active_model_serializers/pull/1560) Update rubocop and address its warnings. (@bf4 @groyoh)
3536
- [#1545](https://github.com/rails-api/active_model_serializers/pull/1545) Document how to pass arbitrary options to the
3637
serializer (@CodedBeardedSignedTaylor)

lib/active_model_serializers/adapter/fragment_cache.rb

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,18 @@ def initialize(adapter, serializer, options)
99
@serializer = serializer
1010
end
1111

12-
# TODO: Use Serializable::Resource
13-
# TODO: call +constantize+ less
1412
# 1. Create a CachedSerializer and NonCachedSerializer from the serializer class
1513
# 2. Serialize the above two with the given adapter
1614
# 3. Pass their serializations to the adapter +::fragment_cache+
1715
def fetch
18-
klass = serializer.class
19-
# It will split the serializer into two, one that will be cached and one that will not
20-
serializers = fragment_serializer(serializer.object.class.name, klass)
21-
22-
# Instantiate both serializers
23-
cached_serializer = serializers[:cached].constantize.new(serializer.object)
24-
non_cached_serializer = serializers[:non_cached].constantize.new(serializer.object)
16+
object = serializer.object
2517

26-
cached_adapter = adapter.class.new(cached_serializer, instance_options)
27-
non_cached_adapter = adapter.class.new(non_cached_serializer, instance_options)
18+
# It will split the serializer into two, one that will be cached and one that will not
19+
serializers = fragment_serializer(object.class.name)
2820

2921
# Get serializable hash from both
30-
cached_hash = cached_adapter.serializable_hash
31-
non_cached_hash = non_cached_adapter.serializable_hash
22+
cached_hash = serialize(object, serializers[:cached])
23+
non_cached_hash = serialize(object, serializers[:non_cached])
3224

3325
# Merge both results
3426
adapter.fragment_cache(cached_hash, non_cached_hash)
@@ -40,31 +32,38 @@ def fetch
4032

4133
private
4234

43-
# Given a serializer class and a hash of its cached and non-cached serializers
35+
def serialize(object, serializer_class)
36+
ActiveModel::SerializableResource.new(
37+
object,
38+
serializer: serializer_class,
39+
adapter: adapter.class
40+
).serializable_hash
41+
end
42+
43+
# Given a hash of its cached and non-cached serializers
4444
# 1. Determine cached attributes from serializer class options
4545
# 2. Add cached attributes to cached Serializer
4646
# 3. Add non-cached attributes to non-cached Serializer
47-
def cached_attributes(klass, serializers)
48-
attributes = serializer.class._attributes
49-
cached_attributes = klass._cache_only ? klass._cache_only : attributes.reject { |attr| klass._cache_except.include?(attr) }
47+
def cache_attributes(serializers)
48+
klass = serializer.class
49+
attributes = klass._attributes
50+
cache_only = klass._cache_only
51+
cached_attributes = cache_only ? cache_only : attributes - klass._cache_except
5052
non_cached_attributes = attributes - cached_attributes
53+
attributes_keys = klass._attributes_keys
5154

52-
cached_attributes.each do |attribute|
53-
options = serializer.class._attributes_keys[attribute]
54-
options ||= {}
55-
# Add cached attributes to cached Serializer
56-
serializers[:cached].constantize.attribute(attribute, options)
57-
end
55+
add_attributes_to_serializer(serializers[:cached], cached_attributes, attributes_keys)
56+
add_attributes_to_serializer(serializers[:non_cached], non_cached_attributes, attributes_keys)
57+
end
5858

59-
non_cached_attributes.each do |attribute|
60-
options = serializer.class._attributes_keys[attribute]
61-
options ||= {}
62-
# Add non-cached attributes to non-cached Serializer
63-
serializers[:non_cached].constantize.attribute(attribute, options)
59+
def add_attributes_to_serializer(serializer, attributes, attributes_keys)
60+
attributes.each do |attribute|
61+
options = attributes_keys[attribute] || {}
62+
serializer.attribute(attribute, options)
6463
end
6564
end
6665

67-
# Given a resource name and its serializer's class
66+
# Given a resource name
6867
# 1. Dyanmically creates a CachedSerializer and NonCachedSerializer
6968
# for a given class 'name'
7069
# 2. Call
@@ -81,30 +80,36 @@ def cached_attributes(klass, serializers)
8180
# User_AdminCachedSerializer
8281
# User_AdminNOnCachedSerializer
8382
#
84-
def fragment_serializer(name, klass)
83+
def fragment_serializer(name)
84+
klass = serializer.class
8585
cached = "#{to_valid_const_name(name)}CachedSerializer"
8686
non_cached = "#{to_valid_const_name(name)}NonCachedSerializer"
8787

88-
Object.const_set cached, Class.new(ActiveModel::Serializer) unless Object.const_defined?(cached)
89-
Object.const_set non_cached, Class.new(ActiveModel::Serializer) unless Object.const_defined?(non_cached)
88+
cached_serializer = get_or_create_serializer(cached)
89+
non_cached_serializer = get_or_create_serializer(non_cached)
9090

9191
klass._cache_options ||= {}
92-
klass._cache_options[:key] = klass._cache_key if klass._cache_key
93-
94-
cached.constantize.cache(klass._cache_options)
92+
cache_key = klass._cache_key
93+
klass._cache_options[:key] = cache_key if cache_key
94+
cached_serializer.cache(klass._cache_options)
9595

96-
# Preserve the type setting in the cached/non-cached serializer classes
97-
cached.constantize.type(klass._type)
98-
non_cached.constantize.type(klass._type)
96+
type = klass._type
97+
cached_serializer.type(type)
98+
non_cached_serializer.type(type)
9999

100-
cached.constantize.fragmented(serializer)
101-
non_cached.constantize.fragmented(serializer)
100+
non_cached_serializer.fragmented(serializer)
101+
cached_serializer.fragmented(serializer)
102102

103-
serializers = { cached: cached, non_cached: non_cached }
104-
cached_attributes(klass, serializers)
103+
serializers = { cached: cached_serializer, non_cached: non_cached_serializer }
104+
cache_attributes(serializers)
105105
serializers
106106
end
107107

108+
def get_or_create_serializer(name)
109+
return Object.const_get(name) if Object.const_defined?(name)
110+
Object.const_set(name, Class.new(ActiveModel::Serializer))
111+
end
112+
108113
def to_valid_const_name(name)
109114
name.gsub('::', '_')
110115
end

0 commit comments

Comments
 (0)