Skip to content

Instantly share code, notes, and snippets.

@sineed sineed/ams.rb
Last active Feb 25, 2019

Embed
What would you like to do?
Upgrade AMS from 0.9.0 to 0.10.0
module AMS
module V09
class Serializer < ActiveModel::Serializer
def serializable_hash(adapter_options = nil,
options = {},
adapter_instance = self.class.serialization_adapter_instance)
object.nil? ? nil : super
end
end
class ArraySerializer < ActiveModel::Serializer::CollectionSerializer
end
class ResourceIdentifier < ActiveModelSerializers::Adapter::JsonApi::ResourceIdentifier
def initialize(serializer, options)
@id = id_for(serializer)
@type = type_for(serializer)
end
private
def id_for(serializer)
serializer.read_attribute_for_serialization(:id)
end
end
class Base < ActiveModelSerializers::Adapter::Base
def initialize(serializer, options = {})
super
@fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
end
private
attr_reader :fieldset
def attributes_for(serializer, fields)
serializer.attributes(fields).except(:id)
end
def resource_object_for(serializer)
resource_object = serializer.fetch(self) do
resource_object = ResourceIdentifier.new(serializer, instance_options).as_json
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
attributes = attributes_for(serializer, requested_fields)
resource_object.merge!(attributes) if attributes.any?
resource_object
end
resource_object
end
end
# represent resource without associations
class Attributes < Base
def serializable_hash(options = nil)
return nil if serializer.nil? || serializer.object.nil?
is_collection = serializer.respond_to?(:each)
serializers = is_collection ? serializer : [serializer]
data = resource_objects_for(serializers)
result = is_collection ? data : data[0]
self.class.transform_key_casing!(result, instance_options)
end
private
def resource_objects_for(serializers)
serializers.map { |serializer| resource_object_for(serializer) }
end
end
class AttributesWithIncluded < Base
def serializable_hash(options = nil)
return {} if serializer.object.nil?
is_collection = serializer.respond_to?(:each)
serializers = is_collection ? serializer : [serializer]
primary_data, included = resource_objects_for(serializers)
hash = {}
hash[root] = is_collection ? primary_data : primary_data[0]
hash[:included] = included if included.any?
hash[meta_key] = meta unless meta.blank?
self.class.transform_key_casing!(hash, instance_options)
end
private
def resource_objects_for(serializers)
@primary = []
@included = {}
@resource_identifiers = Set.new
serializers.each { |serializer| process_resource(serializer) }
serializers.each { |serializer| process_relationships(serializer) }
[@primary, @included]
end
def process_resource(serializer)
return false unless resource_already_processed?(serializer)
@primary << resource_object_for(serializer)
true
end
def process_relationship_resource(serializer, json_key)
return false unless resource_already_processed?(serializer)
@included[json_key] << resource_object_for(serializer)
true
end
def process_relationships(serializer)
serializer.associations.each do |association|
process_relationship(association.serializer, association.key)
end
end
def process_relationship(serializer, key)
json_key = key || serializer.json_key.to_s.pluralize
@included[json_key] ||= []
if serializer.respond_to?(:each)
serializer.each { |s| process_relationship(s, key) }
return
end
return unless serializer && serializer.object
return unless process_relationship_resource(serializer, json_key)
process_relationships(serializer)
end
def resource_already_processed?(serializer)
resource_identifier = ResourceIdentifier.new(serializer, instance_options).as_json
@resource_identifiers.add?(resource_identifier)
end
def meta
instance_options.fetch(:meta, nil)
end
def meta_key
instance_options.fetch(:meta_key, 'meta'.freeze)
end
end
end
end
ActiveModelSerializers::Adapter.register :v09_attributes_with_included, AMS::V09::AttributesWithIncluded
ActiveModelSerializers::Adapter.register :v09_attributes, AMS::V09::Attributes
ActiveModelSerializers.config.adapter = :v09_attributes_with_included

Serializer utilization

Explicit serialization, also change context to scope

-      JSON.parse(
-        ActiveModel::ArraySerializer.new(
-          @categories,
-          each_serializer: CategorySerializer,
-          context: {locale: @locale}
-        ).to_json
-      )
+      ActiveModelSerializers::SerializableResource.new(
+        @categories,
+        each_serializer: CategorySerializer,
+        scope: {locale: @locale}
+      ).serializable_hash

Explicitly set root option

render  json: @accounts,
-                each_serializer: UserSerializer
+                each_serializer: UserSerializer, root: :accounts

Use v09_attributes when I don't need root and included associations

-        LocationSerializer.new(@location, root: false).serializable_hash
+        ActiveModelSerializers::SerializableResource.new(
+          @location,
+          serializer: LocationSerializer,
+          adapter: :v09_attributes
+        ).serializable_hash

Serializer definition

Subclass from V09 serializers

-  class BaseSerializer < ActiveModel::Serializer
-    attributes :id, :type
-
-    def type
-      object.class.model_name.plural
-    end
+  class BaseSerializer < AMS::V09::Serializer

Use type method and provide null id method

-    class EmailSerializer < ActiveModel::Serializer
+    class EmailSerializer < AMS::V09::Serializer
+      type :emails
+      def id
+        nil
+      end

Replace root to key for association, also explicitly define attribute for association

class OrderSerializer < BaseSerializer
-    has_one :consumer, serializer: UserSerializer, root: :users
+    has_one :consumer, serializer: UserSerializer, key: :users
+    attribute :consumer_id,
+    def consumer_id
+      object.consumer_id
+    end
# This is configuration fo 0.9.0 that has been removed
ActiveModel::Serializer.setup do |config|
config.embed = :ids
config.embed_in_root = true
config.embed_in_root_key = :included
end
@oyeanuj

This comment has been minimized.

Copy link

oyeanuj commented Dec 21, 2016

@sineed Thank you for posting the gist! I am in the same boat, and found your gist on the issue you opened in AMS.

If i may, can I ask you a couple of basic questions around your code snippets here?

  1. I was having a hard time getting a hang of the the reasons for having the V09 module - what features were you trying to monkey-patch?

  2. How did you solve the problem of not being able to custom define includes, only, except associations that you could do in AMS 0.9? (rails-api/active_model_serializers#1845 talks about it but it never got merged).

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.