dulead-jsonapi-serializer 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ ::ActiveRecord::Associations::Builder::HasOne.class_eval do
4
+ # Based on
5
+ # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/builder/collection_association.rb#L50
6
+ # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/builder/singular_association.rb#L11
7
+ def self.define_accessors(mixin, reflection)
8
+ super
9
+ name = reflection.name
10
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
11
+ def #{name}_id
12
+ # if an attribute is already defined with this methods name we should just use it
13
+ return read_attribute(__method__) if has_attribute?(__method__)
14
+ association(:#{name}).reader.try(:id)
15
+ end
16
+ CODE
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ require 'fast_jsonapi/scalar'
2
+
3
+ module FastJsonapi
4
+ class Attribute < Scalar; end
5
+ end
@@ -0,0 +1,21 @@
1
+ module FastJsonapi
2
+ class << self
3
+ # Calls either a Proc or a Lambda, making sure to never pass more parameters to it than it can receive
4
+ #
5
+ # @param [Proc] proc the Proc or Lambda to call
6
+ # @param [Array<Object>] *params any number of parameters to be passed to the Proc
7
+ # @return [Object] the result of the Proc call with the supplied parameters
8
+ def call_proc(proc, *params)
9
+ # The parameters array for a lambda created from a symbol (&:foo) differs
10
+ # from explictly defined procs/lambdas, so we can't deduce the number of
11
+ # parameters from the array length (and differs between Ruby 2.x and 3).
12
+ # In the case of negative arity -- unlimited/unknown argument count --
13
+ # just send the object to act as the method receiver.
14
+ if proc.arity.negative?
15
+ proc.call(params.first)
16
+ else
17
+ proc.call(*params.take(proc.parameters.length))
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ require 'skylight'
2
+
3
+ warn('DEPRECATION: Skylight support was moved into the `skylight` gem.')
@@ -0,0 +1,7 @@
1
+ require 'jsonapi/serializer/instrumentation'
2
+
3
+ warn(
4
+ 'DEPRECATION: Performance instrumentation is no longer automatic. See: ' \
5
+ 'https://github.com/jsonapi-serializer/jsonapi-serializer' \
6
+ '#performance-instrumentation'
7
+ )
@@ -0,0 +1,5 @@
1
+ require 'fast_jsonapi/scalar'
2
+
3
+ module FastJsonapi
4
+ class Link < Scalar; end
5
+ end
@@ -0,0 +1,357 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/time'
4
+ require 'active_support/concern'
5
+ require 'active_support/inflector'
6
+ require 'active_support/core_ext/numeric/time'
7
+ require 'fast_jsonapi/helpers'
8
+ require 'fast_jsonapi/attribute'
9
+ require 'fast_jsonapi/relationship'
10
+ require 'fast_jsonapi/link'
11
+ require 'fast_jsonapi/serialization_core'
12
+
13
+ module FastJsonapi
14
+ module ObjectSerializer
15
+ extend ActiveSupport::Concern
16
+ include SerializationCore
17
+
18
+ TRANSFORMS_MAPPING = {
19
+ camel: :camelize,
20
+ camel_lower: [:camelize, :lower],
21
+ dash: :dasherize,
22
+ underscore: :underscore
23
+ }.freeze
24
+
25
+ included do
26
+ # Set record_type based on the name of the serializer class
27
+ set_type(reflected_record_type) if reflected_record_type
28
+ end
29
+
30
+ def initialize(resource, options = {})
31
+ process_options(options)
32
+
33
+ @resource = resource
34
+ end
35
+
36
+ def serializable_hash
37
+ if self.class.is_collection?(@resource, @is_collection)
38
+ return hash_for_collection
39
+ end
40
+
41
+ hash_for_one_record
42
+ end
43
+ alias to_hash serializable_hash
44
+
45
+ def hash_for_one_record
46
+ serializable_hash = { data: nil }
47
+ serializable_hash[:meta] = @meta if @meta.present?
48
+ serializable_hash[:links] = @links if @links.present?
49
+
50
+ return serializable_hash unless @resource
51
+
52
+ serializable_hash[:data] = self.class.record_hash(@resource, @fieldsets[self.class.record_type.to_sym], @includes, @params)
53
+ serializable_hash[:included] = self.class.get_included_records(@resource, @includes, @known_included_objects, @fieldsets, @params) if @includes.present?
54
+ serializable_hash
55
+ end
56
+
57
+ def hash_for_collection
58
+ serializable_hash = {}
59
+
60
+ data = []
61
+ included = []
62
+ fieldset = @fieldsets[self.class.record_type.to_sym]
63
+ @resource.each do |record|
64
+ data << self.class.record_hash(record, fieldset, @includes, @params)
65
+ included.concat self.class.get_included_records(record, @includes, @known_included_objects, @fieldsets, @params) if @includes.present?
66
+ end
67
+
68
+ serializable_hash[:data] = data
69
+ serializable_hash[:included] = included if @includes.present?
70
+ serializable_hash[:meta] = @meta if @meta.present?
71
+ serializable_hash[:links] = @links if @links.present?
72
+ serializable_hash
73
+ end
74
+
75
+ private
76
+
77
+ def process_options(options)
78
+ @fieldsets = deep_symbolize(options[:fields].presence || {})
79
+ @params = {}
80
+
81
+ return if options.blank?
82
+
83
+ @known_included_objects = Set.new
84
+ @meta = options[:meta]
85
+ @links = options[:links]
86
+ @is_collection = options[:is_collection]
87
+ @params = options[:params] || {}
88
+ raise ArgumentError, '`params` option passed to serializer must be a hash' unless @params.is_a?(Hash)
89
+
90
+ if options[:include].present?
91
+ @includes = options[:include].reject(&:blank?).map(&:to_sym)
92
+ self.class.validate_includes!(@includes)
93
+ end
94
+ end
95
+
96
+ def deep_symbolize(collection)
97
+ if collection.is_a? Hash
98
+ collection.each_with_object({}) do |(k, v), hsh|
99
+ hsh[k.to_sym] = deep_symbolize(v)
100
+ end
101
+ elsif collection.is_a? Array
102
+ collection.map { |i| deep_symbolize(i) }
103
+ else
104
+ collection.to_sym
105
+ end
106
+ end
107
+
108
+ class_methods do
109
+ # Detects a collection/enumerable
110
+ #
111
+ # @return [TrueClass] on a successful detection
112
+ def is_collection?(resource, force_is_collection = nil)
113
+ return force_is_collection unless force_is_collection.nil?
114
+
115
+ resource.is_a?(Enumerable) && !resource.respond_to?(:each_pair)
116
+ end
117
+
118
+ def inherited(subclass)
119
+ super(subclass)
120
+ subclass.attributes_to_serialize = attributes_to_serialize.dup if attributes_to_serialize.present?
121
+ subclass.relationships_to_serialize = relationships_to_serialize.dup if relationships_to_serialize.present?
122
+ subclass.cachable_relationships_to_serialize = cachable_relationships_to_serialize.dup if cachable_relationships_to_serialize.present?
123
+ subclass.uncachable_relationships_to_serialize = uncachable_relationships_to_serialize.dup if uncachable_relationships_to_serialize.present?
124
+ subclass.transform_method = transform_method
125
+ subclass.data_links = data_links.dup if data_links.present?
126
+ subclass.cache_store_instance = cache_store_instance
127
+ subclass.cache_store_options = cache_store_options
128
+ subclass.set_type(subclass.reflected_record_type) if subclass.reflected_record_type
129
+ subclass.meta_to_serialize = meta_to_serialize
130
+ subclass.record_id = record_id
131
+ subclass.record_type_block = record_type_block
132
+ end
133
+
134
+ def reflected_record_type
135
+ return @reflected_record_type if defined?(@reflected_record_type)
136
+
137
+ @reflected_record_type ||= begin
138
+ name.split('::').last.chomp('Serializer').underscore.to_sym if name&.end_with?('Serializer')
139
+ end
140
+ end
141
+
142
+ def set_key_transform(transform_name)
143
+ self.transform_method = TRANSFORMS_MAPPING[transform_name.to_sym]
144
+
145
+ # ensure that the record type is correctly transformed
146
+ if record_type
147
+ set_type(record_type)
148
+ # TODO: Remove dead code
149
+ elsif reflected_record_type
150
+ set_type(reflected_record_type)
151
+ end
152
+ end
153
+
154
+ def run_key_transform(input)
155
+ if transform_method.present?
156
+ input.to_s.send(*@transform_method).to_sym
157
+ else
158
+ input.to_sym
159
+ end
160
+ end
161
+
162
+ def use_hyphen
163
+ warn('DEPRECATION WARNING: use_hyphen is deprecated and will be removed from fast_jsonapi 2.0 use (set_key_transform :dash) instead')
164
+ set_key_transform :dash
165
+ end
166
+
167
+ def set_type(type_name)
168
+ self.record_type = run_key_transform(type_name)
169
+ end
170
+
171
+ def set_id(id_name = nil, &block)
172
+ self.record_id = block || id_name
173
+ end
174
+
175
+ def set_record_type_block(&block)
176
+ self.record_type_block = block
177
+ end
178
+
179
+ def cache_options(cache_options)
180
+ # FIXME: remove this if block once deprecated cache_options are not supported anymore
181
+ unless cache_options.key?(:store)
182
+ # fall back to old, deprecated behaviour because no store was passed.
183
+ # we assume the user explicitly wants new behaviour if he passed a
184
+ # store because this is the new syntax.
185
+ deprecated_cache_options(cache_options)
186
+ return
187
+ end
188
+
189
+ self.cache_store_instance = cache_options[:store]
190
+ self.cache_store_options = cache_options.except(:store)
191
+ end
192
+
193
+ # FIXME: remove this method once deprecated cache_options are not supported anymore
194
+ def deprecated_cache_options(cache_options)
195
+ warn('DEPRECATION WARNING: `store:` is a required cache option, we will default to `Rails.cache` for now. See https://github.com/fast-jsonapi/fast_jsonapi#caching for more information.')
196
+
197
+ %i[enabled cache_length].select { |key| cache_options.key?(key) }.each do |key|
198
+ warn("DEPRECATION WARNING: `#{key}` is a deprecated cache option and will have no effect soon. See https://github.com/fast-jsonapi/fast_jsonapi#caching for more information.")
199
+ end
200
+
201
+ self.cache_store_instance = cache_options[:enabled] ? Rails.cache : nil
202
+ self.cache_store_options = {
203
+ expires_in: cache_options[:cache_length] || 5.minutes,
204
+ race_condition_ttl: cache_options[:race_condition_ttl] || 5.seconds
205
+ }
206
+ end
207
+
208
+ def attributes(*attributes_list, &block)
209
+ attributes_list = attributes_list.first if attributes_list.first.class.is_a?(Array)
210
+ options = attributes_list.last.is_a?(Hash) ? attributes_list.pop : {}
211
+ self.attributes_to_serialize = {} if attributes_to_serialize.nil?
212
+
213
+ # to support calling `attribute` with a lambda, e.g `attribute :key, ->(object) { ... }`
214
+ block = attributes_list.pop if attributes_list.last.is_a?(Proc)
215
+
216
+ attributes_list.each do |attr_name|
217
+ method_name = attr_name
218
+ key = run_key_transform(method_name)
219
+ attributes_to_serialize[key] = Attribute.new(
220
+ key: key,
221
+ method: block || method_name,
222
+ options: options
223
+ )
224
+ end
225
+ end
226
+
227
+ alias_method :attribute, :attributes
228
+
229
+ def add_relationship(relationship)
230
+ self.relationships_to_serialize = {} if relationships_to_serialize.nil?
231
+ self.cachable_relationships_to_serialize = {} if cachable_relationships_to_serialize.nil?
232
+ self.uncachable_relationships_to_serialize = {} if uncachable_relationships_to_serialize.nil?
233
+
234
+ # TODO: Remove this undocumented option.
235
+ # Delegate the caching to the serializer exclusively.
236
+ if relationship.cached
237
+ cachable_relationships_to_serialize[relationship.name] = relationship
238
+ else
239
+ uncachable_relationships_to_serialize[relationship.name] = relationship
240
+ end
241
+ relationships_to_serialize[relationship.name] = relationship
242
+ end
243
+
244
+ def has_many(relationship_name, options = {}, &block)
245
+ relationship = create_relationship(relationship_name, :has_many, options, block)
246
+ add_relationship(relationship)
247
+ end
248
+
249
+ def has_one(relationship_name, options = {}, &block)
250
+ relationship = create_relationship(relationship_name, :has_one, options, block)
251
+ add_relationship(relationship)
252
+ end
253
+
254
+ def belongs_to(relationship_name, options = {}, &block)
255
+ relationship = create_relationship(relationship_name, :belongs_to, options, block)
256
+ add_relationship(relationship)
257
+ end
258
+
259
+ def meta(meta_name = nil, &block)
260
+ self.meta_to_serialize = block || meta_name
261
+ end
262
+
263
+ def create_relationship(base_key, relationship_type, options, block)
264
+ name = base_key.to_sym
265
+ if relationship_type == :has_many
266
+ base_serialization_key = base_key.to_s.singularize
267
+ id_postfix = '_ids'
268
+ else
269
+ base_serialization_key = base_key
270
+ id_postfix = '_id'
271
+ end
272
+ polymorphic = fetch_polymorphic_option(options)
273
+
274
+ Relationship.new(
275
+ owner: self,
276
+ key: options[:key] || run_key_transform(base_key),
277
+ name: name,
278
+ id_method_name: compute_id_method_name(
279
+ options[:id_method_name],
280
+ "#{base_serialization_key}#{id_postfix}".to_sym,
281
+ polymorphic,
282
+ options[:serializer],
283
+ block
284
+ ),
285
+ record_type: options[:record_type],
286
+ object_method_name: options[:object_method_name] || name,
287
+ object_block: block,
288
+ serializer: options[:serializer],
289
+ relationship_type: relationship_type,
290
+ cached: options[:cached],
291
+ polymorphic: polymorphic,
292
+ conditional_proc: options[:if],
293
+ transform_method: @transform_method,
294
+ meta: options[:meta],
295
+ links: options[:links],
296
+ lazy_load_data: options[:lazy_load_data]
297
+ )
298
+ end
299
+
300
+ def compute_id_method_name(custom_id_method_name, id_method_name_from_relationship, polymorphic, serializer, block)
301
+ if block.present? || serializer.is_a?(Proc) || polymorphic
302
+ custom_id_method_name || :id
303
+ else
304
+ custom_id_method_name || id_method_name_from_relationship
305
+ end
306
+ end
307
+
308
+ def serializer_for(name)
309
+ namespace = self.name.gsub(/()?\w+Serializer$/, '')
310
+ serializer_name = "#{name.to_s.demodulize.classify}Serializer"
311
+ serializer_class_name = namespace + serializer_name
312
+ begin
313
+ serializer_class_name.constantize
314
+ rescue NameError
315
+ raise NameError, "#{self.name} cannot resolve a serializer class for '#{name}'. " \
316
+ "Attempted to find '#{serializer_class_name}'. " \
317
+ 'Consider specifying the serializer directly through options[:serializer].'
318
+ end
319
+ end
320
+
321
+ def fetch_polymorphic_option(options)
322
+ option = options[:polymorphic]
323
+ return false unless option.present?
324
+ return option if option.respond_to? :keys
325
+
326
+ {}
327
+ end
328
+
329
+ # def link(link_name, link_method_name = nil, &block)
330
+ def link(*params, &block)
331
+ self.data_links = {} if data_links.nil?
332
+
333
+ options = params.last.is_a?(Hash) ? params.pop : {}
334
+ link_name = params.first
335
+ link_method_name = params[-1]
336
+ key = run_key_transform(link_name)
337
+
338
+ data_links[key] = Link.new(
339
+ key: key,
340
+ method: block || link_method_name,
341
+ options: options
342
+ )
343
+ end
344
+
345
+ def validate_includes!(includes)
346
+ return if includes.blank?
347
+
348
+ parse_includes_list(includes).each_key do |include_item|
349
+ relationship_to_include = relationships_to_serialize[include_item]
350
+ raise(JSONAPI::Serializer::UnsupportedIncludeError.new(include_item, name)) unless relationship_to_include
351
+
352
+ relationship_to_include.static_serializer # called for a side-effect to check for a known serializer class.
353
+ end
354
+ end
355
+ end
356
+ end
357
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/railtie'
4
+
5
+ class Railtie < Rails::Railtie
6
+ initializer 'fast_jsonapi.active_record' do
7
+ ActiveSupport.on_load :active_record do
8
+ require 'extensions/has_one'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,236 @@
1
+ module FastJsonapi
2
+ class Relationship
3
+ attr_reader :owner, :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc, :transform_method, :links, :meta, :lazy_load_data
4
+
5
+ def initialize(
6
+ owner:,
7
+ key:,
8
+ name:,
9
+ id_method_name:,
10
+ record_type:,
11
+ object_method_name:,
12
+ object_block:,
13
+ serializer:,
14
+ relationship_type:,
15
+ polymorphic:,
16
+ conditional_proc:,
17
+ transform_method:,
18
+ links:,
19
+ meta:,
20
+ cached: false,
21
+ lazy_load_data: false
22
+ )
23
+ @owner = owner
24
+ @key = key
25
+ @name = name
26
+ @id_method_name = id_method_name
27
+ @record_type = record_type
28
+ @object_method_name = object_method_name
29
+ @object_block = object_block
30
+ @serializer = serializer
31
+ @relationship_type = relationship_type
32
+ @cached = cached
33
+ @polymorphic = polymorphic
34
+ @conditional_proc = conditional_proc
35
+ @transform_method = transform_method
36
+ @links = links || {}
37
+ @meta = meta || {}
38
+ @lazy_load_data = lazy_load_data
39
+ @record_types_for = {}
40
+ @serializers_for_name = {}
41
+ end
42
+
43
+ def serialize(record, included, serialization_params, output_hash)
44
+ if include_relationship?(record, serialization_params)
45
+ empty_case = relationship_type == :has_many ? [] : nil
46
+
47
+ output_hash[key] = {}
48
+ output_hash[key][:data] = ids_hash_from_record_and_relationship(record, serialization_params) || empty_case unless lazy_load_data && !included
49
+
50
+ add_meta_hash(record, serialization_params, output_hash) if meta.present?
51
+ add_links_hash(record, serialization_params, output_hash) if links.present?
52
+ end
53
+ end
54
+
55
+ def fetch_associated_object(record, params)
56
+ return FastJsonapi.call_proc(object_block, record, params) unless object_block.nil?
57
+
58
+ record.send(object_method_name)
59
+ end
60
+
61
+ def include_relationship?(record, serialization_params)
62
+ if conditional_proc.present?
63
+ FastJsonapi.call_proc(conditional_proc, record, serialization_params)
64
+ else
65
+ true
66
+ end
67
+ end
68
+
69
+ def serializer_for(record, serialization_params)
70
+ # TODO: Remove this, dead code...
71
+ if @static_serializer
72
+ @static_serializer
73
+
74
+ elsif polymorphic
75
+ name = polymorphic[record.class] if polymorphic.is_a?(Hash)
76
+ name ||= record.class.name
77
+ serializer_for_name(name)
78
+
79
+ elsif serializer.is_a?(Proc)
80
+ FastJsonapi.call_proc(serializer, record, serialization_params)
81
+
82
+ elsif object_block
83
+ serializer_for_name(record.class.name)
84
+
85
+ else
86
+ # TODO: Remove this, dead code...
87
+ raise "Unknown serializer for object #{record.inspect}"
88
+ end
89
+ end
90
+
91
+ def static_serializer
92
+ initialize_static_serializer unless @initialized_static_serializer
93
+ @static_serializer
94
+ end
95
+
96
+ def static_record_type
97
+ initialize_static_serializer unless @initialized_static_serializer
98
+ @static_record_type
99
+ end
100
+
101
+ private
102
+
103
+ def ids_hash_from_record_and_relationship(record, params = {})
104
+ initialize_static_serializer unless @initialized_static_serializer
105
+
106
+ return ids_hash(fetch_id(record, params), @static_record_type) if @static_record_type
107
+
108
+ return unless associated_object = fetch_associated_object(record, params)
109
+
110
+ if associated_object.respond_to? :map
111
+ return associated_object.map do |object|
112
+ id_hash_from_record object, params
113
+ end
114
+ end
115
+
116
+ id_hash_from_record associated_object, params
117
+ end
118
+
119
+ def id_hash_from_record(record, params)
120
+ associated_record_type = record_type_for(record, params)
121
+ id_hash(record.public_send(id_method_name), associated_record_type)
122
+ end
123
+
124
+ def ids_hash(ids, record_type)
125
+ return ids.map { |id| id_hash(id, record_type) } if ids.respond_to? :map
126
+
127
+ id_hash(ids, record_type) # ids variable is just a single id here
128
+ end
129
+
130
+ def id_hash(id, record_type, default_return = false)
131
+ if id.present?
132
+ { id: id.to_s, type: record_type }
133
+ else
134
+ default_return ? { id: nil, type: record_type } : nil
135
+ end
136
+ end
137
+
138
+ def fetch_id(record, params)
139
+ if object_block.present?
140
+ object = FastJsonapi.call_proc(object_block, record, params)
141
+ return object.map { |item| item.public_send(id_method_name) } if object.respond_to? :map
142
+
143
+ return object.try(id_method_name)
144
+ end
145
+ record.public_send(id_method_name)
146
+ end
147
+
148
+ def add_links_hash(record, params, output_hash)
149
+ output_hash[key][:links] = if links.is_a?(Symbol)
150
+ record.public_send(links)
151
+ else
152
+ links.each_with_object({}) do |(key, method), hash|
153
+ Link.new(key: key, method: method).serialize(record, params, hash)
154
+ end
155
+ end
156
+ end
157
+
158
+ def add_meta_hash(record, params, output_hash)
159
+ output_hash[key][:meta] = if meta.is_a?(Proc)
160
+ FastJsonapi.call_proc(meta, record, params)
161
+ else
162
+ meta
163
+ end
164
+ end
165
+
166
+ def run_key_transform(input)
167
+ if transform_method.present?
168
+ input.to_s.send(*transform_method).to_sym
169
+ else
170
+ input.to_sym
171
+ end
172
+ end
173
+
174
+ def initialize_static_serializer
175
+ return if @initialized_static_serializer
176
+
177
+ @static_serializer = compute_static_serializer
178
+ @static_record_type = compute_static_record_type
179
+ @initialized_static_serializer = true
180
+ end
181
+
182
+ def compute_static_serializer
183
+ if polymorphic
184
+ # polymorphic without a specific serializer --
185
+ # the serializer is determined on a record-by-record basis
186
+ nil
187
+
188
+ elsif serializer.is_a?(Symbol) || serializer.is_a?(String)
189
+ # a serializer was explicitly specified by name -- determine the serializer class
190
+ serializer_for_name(serializer)
191
+
192
+ elsif serializer.is_a?(Proc)
193
+ # the serializer is a Proc to be executed per object -- not static
194
+ nil
195
+
196
+ elsif serializer
197
+ # something else was specified, e.g. a specific serializer class -- return it
198
+ serializer
199
+
200
+ elsif object_block
201
+ # an object block is specified without a specific serializer --
202
+ # assume the objects might be different and infer the serializer by their class
203
+ nil
204
+
205
+ else
206
+ # no serializer information was provided -- infer it from the relationship name
207
+ serializer_name = name.to_s
208
+ serializer_name = serializer_name.singularize if relationship_type.to_sym == :has_many
209
+ serializer_for_name(serializer_name)
210
+ end
211
+ end
212
+
213
+ def serializer_for_name(name)
214
+ @serializers_for_name[name] ||= owner.serializer_for(name)
215
+ end
216
+
217
+ def record_type_for(record, serialization_params)
218
+ # if the record type is static, return it
219
+ return @static_record_type if @static_record_type
220
+
221
+ # if not, use the record type of the serializer, and memoize the transformed version
222
+ serializer = serializer_for(record, serialization_params)
223
+ @record_types_for[serializer] ||= run_key_transform(serializer.record_type)
224
+ end
225
+
226
+ def compute_static_record_type
227
+ if polymorphic
228
+ nil
229
+ elsif record_type
230
+ run_key_transform(record_type)
231
+ elsif @static_serializer
232
+ run_key_transform(@static_serializer.record_type)
233
+ end
234
+ end
235
+ end
236
+ end