Class: Api::V3::SerializerFactory
- Inherits:
-
Object
- Object
- Api::V3::SerializerFactory
- Defined in:
- lib/api/v3/serializer_factory.rb
Class Method Summary collapse
-
.extract_includes(include_spec) ⇒ Object
Parse json_attrs into { assoc_name => spec_or_nil }.
-
.serializer_for(model_class, nested_attrs: nil, parent_name: nil) ⇒ Object
Generate (and cache) a JSONAPI::Serializer subclass for model_class.
Class Method Details
.extract_includes(include_spec) ⇒ Object
Parse json_attrs into { assoc_name => spec_or_nil }. Delegates to Api::ResourceAttributeSet#parsed_includes.
60 61 62 |
# File 'lib/api/v3/serializer_factory.rb', line 60 def self.extract_includes(include_spec) Api::ResourceAttributeSet.new([], [], include_spec).parsed_includes end |
.serializer_for(model_class, nested_attrs: nil, parent_name: nil) ⇒ Object
Generate (and cache) a JSONAPI::Serializer subclass for model_class.
nested_attrs: when set, use these attrs instead of model_class.json_attrs.
Used for included associations — avoids reading the associated model's own
json_attrs and prevents infinite recursion.
parent_name: when set, the generated constant is named
"#{model_class.name}For#{parent_name}Serializer" and include: is NOT
processed (one level deep only).
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/api/v3/serializer_factory.rb', line 12 def self.serializer_for(model_class, nested_attrs: nil, parent_name: nil) const_name = parent_name ? "#{model_class.name}For#{parent_name}Serializer" : "#{model_class.name}Serializer" return Api::V3.const_get(const_name) if Api::V3.const_defined?(const_name) jattrs = nested_attrs || (model_class.respond_to?(:json_attrs) ? (model_class.json_attrs || {}) : {}) attr_set = Api::ResourceAttributeSet.for(model_class, jattrs: jattrs) # Nested serializers are always flat — no recursive includes — to prevent # infinite loops on circular associations (e.g. Role↔User). includes_map = parent_name ? {} : attr_set.parsed_includes type = model_class.model_name.plural.to_sym reflections = model_class.reflect_on_all_associations.each_with_object({}) { |r, h| h[r.name] = r } nested_info = includes_map.each_with_object({}) do |(assoc_name, assoc_spec), hash| reflection = reflections[assoc_name] next unless reflection nested_ser = assoc_spec \ ? serializer_for(reflection.klass, nested_attrs: assoc_spec, parent_name: model_class.name) \ : serializer_for(reflection.klass) hash[assoc_name] = { serializer: nested_ser, macro: reflection.macro } end klass = Class.new do include JSONAPI::Serializer set_type type attributes(*attr_set.attributes) if attr_set.attributes.any? attr_set.methods_list.each do |method_name| attribute(method_name) { |object| object.send(method_name) } end nested_info.each do |assoc_name, info| ser = info[:serializer] case info[:macro] when :has_many then has_many assoc_name, serializer: ser when :has_one then has_one assoc_name, serializer: ser when :belongs_to then belongs_to assoc_name, serializer: ser end end end Api::V3.const_set(const_name, klass) klass end |