7
7
require 'active_model/serializer/fieldset'
8
8
require 'active_model/serializer/lint'
9
9
10
+ # ActiveModel::Serializer is an abstract class that is
11
+ # reified when subclassed to decorate a resource.
10
12
module ActiveModel
11
13
class Serializer
12
14
include Configuration
@@ -44,19 +46,28 @@ def self.digest_caller_file(caller_line)
44
46
45
47
with_options instance_writer : false , instance_reader : false do |serializer |
46
48
class_attribute :_type , instance_reader : true
47
- class_attribute :_attributes
49
+ class_attribute :_attributes # @api private : names of attribute methods, @see Serializer#attribute
48
50
self . _attributes ||= [ ]
49
- class_attribute :_attributes_keys
51
+ class_attribute :_attributes_keys # @api private : maps attribute value to explict key name, @see Serializer#attribute
50
52
self . _attributes_keys ||= { }
51
- serializer . class_attribute :_cache
52
- serializer . class_attribute :_fragmented
53
- serializer . class_attribute :_cache_key
54
- serializer . class_attribute :_cache_only
55
- serializer . class_attribute :_cache_except
56
- serializer . class_attribute :_cache_options
57
- serializer . class_attribute :_cache_digest
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
58
67
end
59
68
69
+ # Serializers inherit _attributes and _attributes_keys.
70
+ # Generates a unique digest for each serializer at load.
60
71
def self . inherited ( base )
61
72
caller_line = caller . first
62
73
base . _attributes = _attributes . dup
@@ -65,10 +76,16 @@ def self.inherited(base)
65
76
super
66
77
end
67
78
79
+ # @example
80
+ # class AdminAuthorSerializer < ActiveModel::Serializer
81
+ # type 'authors'
68
82
def self . type ( type )
69
83
self . _type = type
70
84
end
71
85
86
+ # @example
87
+ # class AdminAuthorSerializer < ActiveModel::Serializer
88
+ # attributes :id, :name, :recent_edits
72
89
def self . attributes ( *attrs )
73
90
attrs = attrs . first if attrs . first . class == Array
74
91
@@ -77,6 +94,14 @@ def self.attributes(*attrs)
77
94
end
78
95
end
79
96
97
+ # @example
98
+ # class AdminAuthorSerializer < ActiveModel::Serializer
99
+ # attributes :id, :recent_edits
100
+ # attribute :name, key: :title
101
+ #
102
+ # def recent_edits
103
+ # object.edits.last(5)
104
+ # enr
80
105
def self . attribute ( attr , options = { } )
81
106
key = options . fetch ( :key , attr )
82
107
_attributes_keys [ attr ] = { key : key } if key != attr
@@ -89,11 +114,35 @@ def self.attribute(attr, options = {})
89
114
end
90
115
end
91
116
117
+ # @api private
118
+ # Used by FragmentCache on the CachedSerializer
119
+ # to call attribute methods on the fragmented cached serializer.
92
120
def self . fragmented ( serializer )
93
121
self . _fragmented = serializer
94
122
end
95
123
96
124
# Enables a serializer to be automatically cached
125
+ #
126
+ # Sets +::_cache+ object to <tt>ActionController::Base.cache_store</tt>
127
+ # when Rails.configuration.action_controller.perform_caching
128
+ #
129
+ # @params options [Hash] with valid keys:
130
+ # key : @see ::_cache_key
131
+ # only : @see ::_cache_only
132
+ # except : @see ::_cache_except
133
+ # skip_digest : does not include digest in cache_key
134
+ # all else : @see ::_cache_options
135
+ #
136
+ # @example
137
+ # class PostSerializer < ActiveModel::Serializer
138
+ # cache key: 'post', expires_in: 3.hours
139
+ # attributes :title, :body
140
+ #
141
+ # has_many :comments
142
+ # end
143
+ #
144
+ # @todo require less code comments. See
145
+ # https://github.com/rails-api/active_model_serializers/pull/1249#issuecomment-146567837
97
146
def self . cache ( options = { } )
98
147
self . _cache = ActionController ::Base . cache_store if Rails . configuration . action_controller . perform_caching
99
148
self . _cache_key = options . delete ( :key )
@@ -102,6 +151,13 @@ def self.cache(options = {})
102
151
self . _cache_options = ( options . empty? ) ? nil : options
103
152
end
104
153
154
+ # @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
155
+ # @return [ActiveModel::Serializer]
156
+ # Preferentially returns
157
+ # 1. resource.serializer
158
+ # 2. ArraySerializer when resource is a collection
159
+ # 3. options[:serializer]
160
+ # 4. lookup serializer when resource is a Class
105
161
def self . serializer_for ( resource , options = { } )
106
162
if resource . respond_to? ( :serializer_class )
107
163
resource . serializer_class
@@ -117,6 +173,8 @@ def self.adapter
117
173
ActiveModel ::Serializer ::Adapter . lookup ( config . adapter )
118
174
end
119
175
176
+ # Used to cache serializer name => serializer class
177
+ # when looked up by Serializer.get_serializer_for.
120
178
def self . serializers_cache
121
179
@serializers_cache ||= ThreadSafe ::Cache . new
122
180
end
@@ -136,6 +194,11 @@ def self.serializer_lookup_chain_for(klass)
136
194
end
137
195
138
196
# @api private
197
+ # Find a serializer from a class and caches the lookup.
198
+ # Preferentially retuns:
199
+ # 1. class name appended with "Serializer"
200
+ # 2. try again with superclass, if present
201
+ # 3. nil
139
202
def self . get_serializer_for ( klass )
140
203
serializers_cache . fetch_or_store ( klass ) do
141
204
# NOTE(beauby): When we drop 1.9.3 support we can lazify the map for perfs.
@@ -151,6 +214,9 @@ def self.get_serializer_for(klass)
151
214
152
215
attr_accessor :object , :root , :scope
153
216
217
+ # `scope_name` is set as :current_user by default in the controller.
218
+ # If the instance does not have a method named `scope_name`, it
219
+ # defines the method so that it calls the +scope+.
154
220
def initialize ( object , options = { } )
155
221
self . object = object
156
222
self . instance_options = options
@@ -165,10 +231,13 @@ def initialize(object, options = {})
165
231
end
166
232
end
167
233
234
+ # Used by adapter as resource root.
168
235
def json_key
169
236
root || object . class . model_name . to_s . underscore
170
237
end
171
238
239
+ # Return the +attributes+ of +object+ as presented
240
+ # by the serializer.
172
241
def attributes
173
242
attributes = self . class . _attributes . dup
174
243
0 commit comments