mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-25 07:16:49 +00:00
Remove everything, rewrite of AMS starts here
This commit is contained in:
@@ -1,58 +0,0 @@
|
||||
module ActionController
|
||||
# Action Controller Serialization
|
||||
#
|
||||
# Overrides render :json to check if the given object implements +active_model_serializer+
|
||||
# as a method. If so, use the returned serializer instead of calling +to_json+ on the object.
|
||||
#
|
||||
# This module also provides a serialization_scope method that allows you to configure the
|
||||
# +serialization_scope+ of the serializer. Most apps will likely set the +serialization_scope+
|
||||
# to the current user:
|
||||
#
|
||||
# class ApplicationController < ActionController::Base
|
||||
# serialization_scope :current_user
|
||||
# end
|
||||
#
|
||||
# If you need more complex scope rules, you can simply override the serialization_scope:
|
||||
#
|
||||
# class ApplicationController < ActionController::Base
|
||||
# private
|
||||
#
|
||||
# def serialization_scope
|
||||
# current_user
|
||||
# end
|
||||
# end
|
||||
#
|
||||
module Serialization
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include ActionController::Renderers
|
||||
|
||||
included do
|
||||
class_attribute :_serialization_scope
|
||||
self._serialization_scope = :current_user
|
||||
end
|
||||
|
||||
def serialization_scope
|
||||
send(_serialization_scope) if _serialization_scope && respond_to?(_serialization_scope, true)
|
||||
end
|
||||
|
||||
def default_serializer_options
|
||||
end
|
||||
|
||||
def _render_option_json(resource, options)
|
||||
json = ActiveModel::Serializer.build_json(self, resource, options)
|
||||
|
||||
if json
|
||||
super(json, options)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def serialization_scope(scope)
|
||||
self._serialization_scope = scope
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,65 +0,0 @@
|
||||
require 'active_model/serializable'
|
||||
require 'active_model/serializer/caching'
|
||||
require "active_support/core_ext/class/attribute"
|
||||
require 'active_support/dependencies'
|
||||
require 'active_support/descendants_tracker'
|
||||
|
||||
module ActiveModel
|
||||
# Active Model Array Serializer
|
||||
#
|
||||
# Serializes an Array, checking if each element implements
|
||||
# the +active_model_serializer+ method.
|
||||
#
|
||||
# To disable serialization of root elements:
|
||||
#
|
||||
# ActiveModel::ArraySerializer.root = false
|
||||
#
|
||||
class ArraySerializer
|
||||
extend ActiveSupport::DescendantsTracker
|
||||
|
||||
include ActiveModel::Serializable
|
||||
include ActiveModel::Serializer::Caching
|
||||
|
||||
attr_reader :object, :options
|
||||
|
||||
class_attribute :root
|
||||
|
||||
class_attribute :cache
|
||||
class_attribute :perform_caching
|
||||
|
||||
class << self
|
||||
# set perform caching like root
|
||||
def cached(value = true)
|
||||
self.perform_caching = value
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(object, options={})
|
||||
@object = object
|
||||
@options = options
|
||||
end
|
||||
|
||||
def serialize_object
|
||||
serializable_array
|
||||
end
|
||||
|
||||
def serializable_array
|
||||
object.map do |item|
|
||||
if options.has_key? :each_serializer
|
||||
serializer = options[:each_serializer]
|
||||
elsif item.respond_to?(:active_model_serializer)
|
||||
serializer = item.active_model_serializer
|
||||
end
|
||||
serializer ||= DefaultSerializer
|
||||
|
||||
serializable = serializer.new(item, options.merge(root: nil))
|
||||
|
||||
if serializable.respond_to?(:serializable_hash)
|
||||
serializable.serializable_hash
|
||||
else
|
||||
serializable.as_json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,49 +0,0 @@
|
||||
require 'active_support/core_ext/object/to_json'
|
||||
|
||||
module ActiveModel
|
||||
# Enable classes to Classes including this module to serialize themselves by implementing a serialize method and an options method.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# require 'active_model_serializers'
|
||||
#
|
||||
# class MySerializer
|
||||
# include ActiveModel::Serializable
|
||||
#
|
||||
# def initialize
|
||||
# @options = {}
|
||||
# end
|
||||
#
|
||||
# attr_reader :options
|
||||
#
|
||||
# def serialize
|
||||
# { a: 1 }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# puts MySerializer.new.to_json
|
||||
module Serializable
|
||||
def as_json(args={})
|
||||
if root = args[:root] || options[:root]
|
||||
options[:hash] = hash = {}
|
||||
options[:unique_values] = {}
|
||||
|
||||
hash.merge!(root => serialize)
|
||||
include_meta hash
|
||||
hash
|
||||
else
|
||||
serialize
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def include_meta(hash)
|
||||
hash[meta_key] = options[:meta] if options.has_key?(:meta)
|
||||
end
|
||||
|
||||
def meta_key
|
||||
options[:meta_key].try(:to_sym) || :meta
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,475 +0,0 @@
|
||||
require 'active_model/serializable'
|
||||
require 'active_model/serializer/caching'
|
||||
require "active_support/core_ext/class/attribute"
|
||||
require "active_support/core_ext/module/anonymous"
|
||||
require 'active_support/dependencies'
|
||||
require 'active_support/descendants_tracker'
|
||||
|
||||
module ActiveModel
|
||||
# Active Model Serializer
|
||||
#
|
||||
# Provides a basic serializer implementation that allows you to easily
|
||||
# control how a given object is going to be serialized. On initialization,
|
||||
# it expects two objects as arguments, a resource and options. For example,
|
||||
# one may do in a controller:
|
||||
#
|
||||
# PostSerializer.new(@post, scope: current_user).to_json
|
||||
#
|
||||
# The object to be serialized is the +@post+ and the current user is passed
|
||||
# in for authorization purposes.
|
||||
#
|
||||
# We use the scope to check if a given attribute should be serialized or not.
|
||||
# For example, some attributes may only be returned if +current_user+ is the
|
||||
# author of the post:
|
||||
#
|
||||
# class PostSerializer < ActiveModel::Serializer
|
||||
# attributes :title, :body
|
||||
# has_many :comments
|
||||
#
|
||||
# private
|
||||
#
|
||||
# def attributes
|
||||
# hash = super
|
||||
# hash.merge!(email: post.email) if author?
|
||||
# hash
|
||||
# end
|
||||
#
|
||||
# def author?
|
||||
# post.author == scope
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class Serializer
|
||||
extend ActiveSupport::DescendantsTracker
|
||||
|
||||
include ActiveModel::Serializable
|
||||
include ActiveModel::Serializer::Caching
|
||||
|
||||
INCLUDE_METHODS = {}
|
||||
INSTRUMENT = { serialize: :"serialize.serializer", associations: :"associations.serializer" }
|
||||
|
||||
class IncludeError < StandardError
|
||||
attr_reader :source, :association
|
||||
|
||||
def initialize(source, association)
|
||||
@source, @association = source, association
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Cannot serialize #{association} when #{source} does not have a root!"
|
||||
end
|
||||
end
|
||||
|
||||
class_attribute :_attributes
|
||||
self._attributes = {}
|
||||
|
||||
class_attribute :_associations
|
||||
self._associations = {}
|
||||
|
||||
class_attribute :_root
|
||||
class_attribute :_embed
|
||||
self._embed = :objects
|
||||
class_attribute :_root_embed
|
||||
|
||||
class_attribute :cache
|
||||
class_attribute :perform_caching
|
||||
|
||||
class << self
|
||||
def cached(value = true)
|
||||
self.perform_caching = value
|
||||
end
|
||||
|
||||
# Define attributes to be used in the serialization.
|
||||
def attributes(*attrs)
|
||||
|
||||
self._attributes = _attributes.dup
|
||||
|
||||
attrs.each do |attr|
|
||||
if Hash === attr
|
||||
attr.each {|attr_real, key| attribute(attr_real, key: key) }
|
||||
else
|
||||
attribute attr
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def attribute(attr, options={})
|
||||
self._attributes = _attributes.merge(attr.is_a?(Hash) ? attr : {attr => options[:key] || attr.to_s.gsub(/\?$/, '').to_sym})
|
||||
|
||||
attr = attr.keys[0] if attr.is_a? Hash
|
||||
|
||||
unless method_defined?(attr)
|
||||
define_method attr do
|
||||
object.read_attribute_for_serialization(attr.to_sym)
|
||||
end
|
||||
end
|
||||
|
||||
define_include_method attr
|
||||
|
||||
# protect inheritance chains and open classes
|
||||
# if a serializer inherits from another OR
|
||||
# attributes are added later in a classes lifecycle
|
||||
# poison the cache
|
||||
define_method :_fast_attributes do
|
||||
raise NameError
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def associate(klass, attrs) #:nodoc:
|
||||
options = attrs.extract_options!
|
||||
self._associations = _associations.dup
|
||||
|
||||
attrs.each do |attr|
|
||||
unless method_defined?(attr)
|
||||
define_method attr do
|
||||
object.send attr
|
||||
end
|
||||
end
|
||||
|
||||
define_include_method attr
|
||||
|
||||
self._associations[attr] = [klass, options]
|
||||
end
|
||||
end
|
||||
|
||||
def define_include_method(name)
|
||||
method = "include_#{name}?".to_sym
|
||||
|
||||
INCLUDE_METHODS[name] = method
|
||||
|
||||
unless method_defined?(method)
|
||||
define_method method do
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Defines an association in the object should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an array when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def has_many(*attrs)
|
||||
associate(Association::HasMany, attrs)
|
||||
end
|
||||
|
||||
# Defines an association in the object should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an object when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def has_one(*attrs)
|
||||
associate(Association::HasOne, attrs)
|
||||
end
|
||||
|
||||
# Return a schema hash for the current serializer. This information
|
||||
# can be used to generate clients for the serialized output.
|
||||
#
|
||||
# The schema hash has two keys: +attributes+ and +associations+.
|
||||
#
|
||||
# The +attributes+ hash looks like this:
|
||||
#
|
||||
# { name: :string, age: :integer }
|
||||
#
|
||||
# The +associations+ hash looks like this:
|
||||
# { posts: { has_many: :posts } }
|
||||
#
|
||||
# If :key is used:
|
||||
#
|
||||
# class PostsSerializer < ActiveModel::Serializer
|
||||
# has_many :posts, key: :my_posts
|
||||
# end
|
||||
#
|
||||
# the hash looks like this:
|
||||
#
|
||||
# { my_posts: { has_many: :posts }
|
||||
#
|
||||
# This information is extracted from the serializer's model class,
|
||||
# which is provided by +SerializerClass.model_class+.
|
||||
#
|
||||
# The schema method uses the +columns_hash+ and +reflect_on_association+
|
||||
# methods, provided by default by ActiveRecord. You can implement these
|
||||
# methods on your custom models if you want the serializer's schema method
|
||||
# to work.
|
||||
#
|
||||
# TODO: This is currently coupled to Active Record. We need to
|
||||
# figure out a way to decouple those two.
|
||||
def schema
|
||||
klass = model_class
|
||||
columns = klass.columns_hash
|
||||
|
||||
attrs = {}
|
||||
_attributes.each do |name, key|
|
||||
if column = columns[name.to_s]
|
||||
attrs[key] = column.type
|
||||
else
|
||||
# Computed attribute (method on serializer or model). We cannot
|
||||
# infer the type, so we put nil, unless specified in the attribute declaration
|
||||
if name != key
|
||||
attrs[name] = key
|
||||
else
|
||||
attrs[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
associations = {}
|
||||
_associations.each do |attr, (association_class, options)|
|
||||
association = association_class.new(attr, options)
|
||||
|
||||
if model_association = klass.reflect_on_association(association.name)
|
||||
# Real association.
|
||||
associations[association.key] = { model_association.macro => model_association.name }
|
||||
else
|
||||
# Computed association. We could infer has_many vs. has_one from
|
||||
# the association class, but that would make it different from
|
||||
# real associations, which read has_one vs. belongs_to from the
|
||||
# model.
|
||||
associations[association.key] = nil
|
||||
end
|
||||
end
|
||||
|
||||
{ attributes: attrs, associations: associations }
|
||||
end
|
||||
|
||||
# The model class associated with this serializer.
|
||||
def model_class
|
||||
name.sub(/Serializer$/, '').constantize
|
||||
end
|
||||
|
||||
# Define how associations should be embedded.
|
||||
#
|
||||
# embed :objects # Embed associations as full objects
|
||||
# embed :ids # Embed only the association ids
|
||||
# embed :ids, include: true # Embed the association ids and include objects in the root
|
||||
#
|
||||
def embed(type, options={})
|
||||
self._embed = type
|
||||
self._root_embed = true if options[:include]
|
||||
end
|
||||
|
||||
# Defines the root used on serialization. If false, disables the root.
|
||||
def root(name)
|
||||
self._root = name
|
||||
end
|
||||
alias_method :root=, :root
|
||||
|
||||
# Used internally to create a new serializer object based on controller
|
||||
# settings and options for a given resource. These settings are typically
|
||||
# set during the request lifecycle or by the controller class, and should
|
||||
# not be manually defined for this method.
|
||||
def build_json(controller, resource, options)
|
||||
default_options = controller.send(:default_serializer_options) || {}
|
||||
options = default_options.merge(options || {})
|
||||
|
||||
serializer = options.delete(:serializer) ||
|
||||
(resource.respond_to?(:active_model_serializer) &&
|
||||
resource.active_model_serializer)
|
||||
|
||||
return serializer unless serializer
|
||||
|
||||
if resource.respond_to?(:to_ary)
|
||||
unless serializer <= ActiveModel::ArraySerializer
|
||||
raise ArgumentError.new("#{serializer.name} is not an ArraySerializer. " +
|
||||
"You may want to use the :each_serializer option instead.")
|
||||
end
|
||||
|
||||
if options[:root] != false && serializer.root != false
|
||||
# the serializer for an Array is ActiveModel::ArraySerializer
|
||||
options[:root] ||= serializer.root || controller.controller_name
|
||||
end
|
||||
end
|
||||
|
||||
options[:scope] = controller.serialization_scope unless options.has_key?(:scope)
|
||||
options[:scope_name] = controller._serialization_scope unless options.has_key?(:scope_name)
|
||||
options[:url_options] = controller.url_options
|
||||
|
||||
serializer.new(resource, options)
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :object, :options
|
||||
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
|
||||
scope_name = @options[:scope_name]
|
||||
if scope_name && !respond_to?(scope_name)
|
||||
self.class.class_eval do
|
||||
define_method scope_name, lambda { scope }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def root_name
|
||||
return false if self._root == false
|
||||
|
||||
class_name = self.class.name.demodulize.underscore.sub(/_serializer$/, '').to_sym unless self.class.name.blank?
|
||||
|
||||
if self._root == true
|
||||
class_name
|
||||
else
|
||||
self._root || class_name
|
||||
end
|
||||
end
|
||||
|
||||
def url_options
|
||||
@options[:url_options] || {}
|
||||
end
|
||||
|
||||
# Returns a json representation of the serializable
|
||||
# object including the root.
|
||||
def as_json(args={})
|
||||
super(root: args.fetch(:root, options.fetch(:root, root_name)))
|
||||
end
|
||||
|
||||
def serialize_object
|
||||
serializable_hash
|
||||
end
|
||||
|
||||
# Returns a hash representation of the serializable
|
||||
# object without the root.
|
||||
def serializable_hash
|
||||
return nil if @object.nil?
|
||||
@node = attributes
|
||||
include_associations! if _embed
|
||||
@node
|
||||
end
|
||||
|
||||
def include_associations!
|
||||
_associations.each_key do |name|
|
||||
include!(name) if include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
def include?(name)
|
||||
return false if @options.key?(:only) && !Array(@options[:only]).include?(name)
|
||||
return false if @options.key?(:except) && Array(@options[:except]).include?(name)
|
||||
send INCLUDE_METHODS[name]
|
||||
end
|
||||
|
||||
def include!(name, options={})
|
||||
hash = @options[:hash]
|
||||
unique_values = @options[:unique_values] ||= {}
|
||||
|
||||
node = options[:node] ||= @node
|
||||
value = options[:value]
|
||||
|
||||
if options[:include] == nil
|
||||
if @options.key?(:include)
|
||||
options[:include] = @options[:include].include?(name)
|
||||
elsif @options.include?(:exclude)
|
||||
options[:include] = !@options[:exclude].include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
klass, klass_options = _associations[name]
|
||||
association_class =
|
||||
if klass
|
||||
options = klass_options.merge options
|
||||
klass
|
||||
elsif value.respond_to?(:to_ary)
|
||||
Association::HasMany
|
||||
else
|
||||
Association::HasOne
|
||||
end
|
||||
|
||||
options = default_embed_options.merge!(options)
|
||||
options[:value] ||= send(name)
|
||||
association = association_class.new(name, options, self.options)
|
||||
|
||||
if association.embed_ids?
|
||||
node[association.key] = association.serialize_ids
|
||||
|
||||
if association.embed_in_root? && hash.nil?
|
||||
raise IncludeError.new(self.class, association.name)
|
||||
elsif association.embed_in_root? && association.embeddable?
|
||||
merge_association hash, association.root, association.serializables, unique_values
|
||||
end
|
||||
elsif association.embed_objects?
|
||||
node[association.key] = association.serialize
|
||||
end
|
||||
end
|
||||
|
||||
# In some cases, an Array of associations is built by merging the associated
|
||||
# content for all of the children. For instance, if a Post has_many comments,
|
||||
# which has_many tags, the top-level :tags key will contain the merged list
|
||||
# of all tags for all comments of the post.
|
||||
#
|
||||
# In order to make this efficient, we store a :unique_values hash containing
|
||||
# a unique list of all of the objects that are already in the Array. This
|
||||
# avoids the need to scan through the Array looking for entries every time
|
||||
# we want to merge a new list of values.
|
||||
def merge_association(hash, key, serializables, unique_values)
|
||||
already_serialized = (unique_values[key] ||= {})
|
||||
serializable_hashes = (hash[key] ||= [])
|
||||
|
||||
serializables.each do |serializable|
|
||||
unless already_serialized.include? serializable.object
|
||||
already_serialized[serializable.object] = true
|
||||
serializable_hashes << serializable.serializable_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a hash representation of the serializable
|
||||
# object attributes.
|
||||
def attributes
|
||||
_fast_attributes
|
||||
rescue NameError
|
||||
method = "def _fast_attributes\n"
|
||||
|
||||
method << " h = {}\n"
|
||||
|
||||
_attributes.each do |name,key|
|
||||
method << " h[:\"#{key}\"] = read_attribute_for_serialization(:\"#{name}\") if include?(:\"#{name}\")\n"
|
||||
end
|
||||
method << " h\nend"
|
||||
|
||||
self.class.class_eval method
|
||||
_fast_attributes
|
||||
end
|
||||
|
||||
# Returns options[:scope]
|
||||
def scope
|
||||
@options[:scope]
|
||||
end
|
||||
|
||||
alias :read_attribute_for_serialization :send
|
||||
|
||||
# Use ActiveSupport::Notifications to send events to external systems.
|
||||
# The event name is: name.class_name.serializer
|
||||
def instrument(name, payload = {}, &block)
|
||||
event_name = INSTRUMENT[name]
|
||||
ActiveSupport::Notifications.instrument(event_name, payload, &block)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_embed_options
|
||||
{
|
||||
embed: _embed,
|
||||
include: _root_embed
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# DefaultSerializer
|
||||
#
|
||||
# Provides a constant interface for all items, particularly
|
||||
# for ArraySerializer.
|
||||
class DefaultSerializer
|
||||
attr_reader :object, :options
|
||||
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
end
|
||||
|
||||
def serializable_hash
|
||||
@object.as_json(@options)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,185 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Association #:nodoc:
|
||||
# name: The name of the association.
|
||||
#
|
||||
# options: A hash. These keys are accepted:
|
||||
#
|
||||
# value: The object we're associating with.
|
||||
#
|
||||
# serializer: The class used to serialize the association.
|
||||
#
|
||||
# embed: Define how associations should be embedded.
|
||||
# - :objects # Embed associations as full objects.
|
||||
# - :ids # Embed only the association ids.
|
||||
# - :ids, include: true # Embed the association ids and include objects in the root.
|
||||
#
|
||||
# include: Used in conjunction with embed :ids. Includes the objects in the root.
|
||||
#
|
||||
# root: Used in conjunction with include: true. Defines the key used to embed the objects.
|
||||
#
|
||||
# key: Key name used to store the ids in.
|
||||
#
|
||||
# embed_key: Method used to fetch ids. Defaults to :id.
|
||||
#
|
||||
# polymorphic: Is the association is polymorphic?. Values: true or false.
|
||||
def initialize(name, options={}, serializer_options={})
|
||||
@name = name
|
||||
@object = options[:value]
|
||||
|
||||
embed = options[:embed]
|
||||
@embed_ids = embed == :id || embed == :ids
|
||||
@embed_objects = embed == :object || embed == :objects
|
||||
@embed_key = options[:embed_key] || :id
|
||||
@embed_in_root = options[:include]
|
||||
|
||||
serializer = options[:serializer]
|
||||
@serializer_class = serializer.is_a?(String) ? serializer.constantize : serializer
|
||||
|
||||
@options = options
|
||||
@serializer_options = serializer_options
|
||||
end
|
||||
|
||||
attr_reader :object, :root, :name, :embed_ids, :embed_objects, :embed_in_root
|
||||
alias embeddable? object
|
||||
alias embed_objects? embed_objects
|
||||
alias embed_ids? embed_ids
|
||||
alias use_id_key? embed_ids?
|
||||
alias embed_in_root? embed_in_root
|
||||
|
||||
def key
|
||||
if key = options[:key]
|
||||
key
|
||||
elsif use_id_key?
|
||||
id_key
|
||||
else
|
||||
name
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :embed_key, :serializer_class, :options, :serializer_options
|
||||
|
||||
def find_serializable(object)
|
||||
if serializer_class
|
||||
serializer_class.new(object, serializer_options)
|
||||
elsif object.respond_to?(:active_model_serializer) && (ams = object.active_model_serializer)
|
||||
ams.new(object, serializer_options)
|
||||
else
|
||||
object
|
||||
end
|
||||
end
|
||||
|
||||
class HasMany < Association #:nodoc:
|
||||
def root
|
||||
options[:root] || name
|
||||
end
|
||||
|
||||
def id_key
|
||||
"#{name.to_s.singularize}_ids".to_sym
|
||||
end
|
||||
|
||||
def serializables
|
||||
object.map do |item|
|
||||
find_serializable(item)
|
||||
end
|
||||
end
|
||||
|
||||
def serialize
|
||||
object.map do |item|
|
||||
find_serializable(item).serializable_hash
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_ids
|
||||
object.map do |item|
|
||||
serializer = find_serializable(item)
|
||||
if serializer.respond_to?(embed_key)
|
||||
serializer.send(embed_key)
|
||||
else
|
||||
item.read_attribute_for_serialization(embed_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class HasOne < Association #:nodoc:
|
||||
def initialize(name, options={}, serializer_options={})
|
||||
super
|
||||
@polymorphic = options[:polymorphic]
|
||||
end
|
||||
|
||||
def root
|
||||
if root = options[:root]
|
||||
root
|
||||
elsif polymorphic?
|
||||
object.class.to_s.pluralize.demodulize.underscore.to_sym
|
||||
else
|
||||
name.to_s.pluralize.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
def id_key
|
||||
"#{name}_id".to_sym
|
||||
end
|
||||
|
||||
def embeddable?
|
||||
super || !polymorphic?
|
||||
end
|
||||
|
||||
def serializables
|
||||
value = object && find_serializable(object)
|
||||
value ? [value] : []
|
||||
end
|
||||
|
||||
def serialize
|
||||
if object
|
||||
if polymorphic?
|
||||
{
|
||||
:type => polymorphic_key,
|
||||
polymorphic_key => find_serializable(object).serializable_hash
|
||||
}
|
||||
else
|
||||
find_serializable(object).serializable_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_ids
|
||||
if object
|
||||
serializer = find_serializable(object)
|
||||
id =
|
||||
if serializer.respond_to?(embed_key)
|
||||
serializer.send(embed_key)
|
||||
else
|
||||
object.read_attribute_for_serialization(embed_key)
|
||||
end
|
||||
|
||||
if polymorphic?
|
||||
{
|
||||
type: polymorphic_key,
|
||||
id: id
|
||||
}
|
||||
else
|
||||
id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :polymorphic
|
||||
alias polymorphic? polymorphic
|
||||
|
||||
def use_id_key?
|
||||
embed_ids? && !polymorphic?
|
||||
end
|
||||
|
||||
def polymorphic_key
|
||||
object.class.to_s.demodulize.underscore.to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,37 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Caching
|
||||
def to_json(*args)
|
||||
if caching_enabled?
|
||||
key = expand_cache_key([self.class.to_s.underscore, cache_key, 'to-json'])
|
||||
cache.fetch key do
|
||||
super
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def serialize(*args)
|
||||
if caching_enabled?
|
||||
key = expand_cache_key([self.class.to_s.underscore, cache_key, 'serialize'])
|
||||
cache.fetch key do
|
||||
serialize_object
|
||||
end
|
||||
else
|
||||
serialize_object
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def caching_enabled?
|
||||
perform_caching && cache && respond_to?(:cache_key)
|
||||
end
|
||||
|
||||
def expand_cache_key(*args)
|
||||
ActiveSupport::Cache.expand_cache_key(args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
VERSION = "0.8.1"
|
||||
end
|
||||
end
|
||||
@@ -1,95 +0,0 @@
|
||||
require "active_support"
|
||||
require "active_support/core_ext/string/inflections"
|
||||
require "active_support/notifications"
|
||||
require "active_model"
|
||||
require "active_model/array_serializer"
|
||||
require "active_model/serializer"
|
||||
require "active_model/serializer/associations"
|
||||
require "set"
|
||||
|
||||
if defined?(Rails)
|
||||
module ActiveModel
|
||||
class Railtie < Rails::Railtie
|
||||
generators do |app|
|
||||
Rails::Generators.configure!(app.config.generators)
|
||||
Rails::Generators.hidden_namespaces.uniq!
|
||||
require_relative "generators/resource_override"
|
||||
end
|
||||
|
||||
initializer "include_routes.active_model_serializer" do |app|
|
||||
ActiveSupport.on_load(:active_model_serializers) do
|
||||
include AbstractController::UrlFor
|
||||
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
|
||||
include app.routes.mounted_helpers
|
||||
end
|
||||
end
|
||||
|
||||
initializer "caching.active_model_serializer" do |app|
|
||||
ActiveModel::Serializer.perform_caching = app.config.action_controller.perform_caching
|
||||
ActiveModel::ArraySerializer.perform_caching = app.config.action_controller.perform_caching
|
||||
|
||||
ActiveModel::Serializer.cache = Rails.cache
|
||||
ActiveModel::ArraySerializer.cache = Rails.cache
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveModel::SerializerSupport
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods #:nodoc:
|
||||
if "".respond_to?(:safe_constantize)
|
||||
def active_model_serializer
|
||||
"#{self.name}Serializer".safe_constantize
|
||||
end
|
||||
else
|
||||
def active_model_serializer
|
||||
begin
|
||||
"#{self.name}Serializer".constantize
|
||||
rescue NameError => e
|
||||
raise unless e.message =~ /uninitialized constant/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a model serializer for this object considering its namespace.
|
||||
def active_model_serializer
|
||||
self.class.active_model_serializer
|
||||
end
|
||||
|
||||
alias :read_attribute_for_serialization :send
|
||||
end
|
||||
|
||||
module ActiveModel::ArraySerializerSupport
|
||||
def active_model_serializer
|
||||
ActiveModel::ArraySerializer
|
||||
end
|
||||
end
|
||||
|
||||
Array.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
Set.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
|
||||
{
|
||||
active_record: 'ActiveRecord::Relation',
|
||||
mongoid: 'Mongoid::Criteria'
|
||||
}.each do |orm, rel_class|
|
||||
ActiveSupport.on_load(orm) do
|
||||
include ActiveModel::SerializerSupport
|
||||
rel_class.constantize.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
require 'action_controller'
|
||||
require 'action_controller/serialization'
|
||||
|
||||
ActiveSupport.on_load(:action_controller) do
|
||||
include ::ActionController::Serialization
|
||||
end
|
||||
rescue LoadError => ex
|
||||
# rails on installed, continuing
|
||||
end
|
||||
|
||||
ActiveSupport.run_load_hooks(:active_model_serializers, ActiveModel::Serializer)
|
||||
@@ -1,16 +0,0 @@
|
||||
# We do not recommend that you use AM::S in this way, but if you must, here
|
||||
# is a mixin that overrides ActiveRecord::Base#to_json and #as_json.
|
||||
|
||||
module ActiveRecord
|
||||
module SerializerOverride
|
||||
def to_json options = {}
|
||||
active_model_serializer.new(self).to_json options
|
||||
end
|
||||
|
||||
def as_json options={}
|
||||
active_model_serializer.new(self).as_json options
|
||||
end
|
||||
end
|
||||
|
||||
Base.send(:include, SerializerOverride)
|
||||
end
|
||||
@@ -1,13 +0,0 @@
|
||||
require "rails/generators"
|
||||
require "rails/generators/rails/resource/resource_generator"
|
||||
|
||||
module Rails
|
||||
module Generators
|
||||
ResourceGenerator.class_eval do
|
||||
def add_serializer
|
||||
invoke "serializer"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
Description:
|
||||
Generates a serializer for the given resource with tests.
|
||||
|
||||
Example:
|
||||
`rails generate serializer Account name created_at`
|
||||
|
||||
For TestUnit it creates:
|
||||
Serializer: app/serializers/account_serializer.rb
|
||||
TestUnit: test/unit/account_serializer_test.rb
|
||||
@@ -1,36 +0,0 @@
|
||||
module Rails
|
||||
module Generators
|
||||
class SerializerGenerator < NamedBase
|
||||
source_root File.expand_path("../templates", __FILE__)
|
||||
check_class_collision suffix: "Serializer"
|
||||
|
||||
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
||||
|
||||
class_option :parent, type: :string, desc: "The parent class for the generated serializer"
|
||||
|
||||
def create_serializer_file
|
||||
template 'serializer.rb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def attributes_names
|
||||
[:id] + attributes.select { |attr| !attr.reference? }.map { |a| a.name.to_sym }
|
||||
end
|
||||
|
||||
def association_names
|
||||
attributes.select { |attr| attr.reference? }.map { |a| a.name.to_sym }
|
||||
end
|
||||
|
||||
def parent_class_name
|
||||
if options[:parent]
|
||||
options[:parent]
|
||||
elsif defined?(::ApplicationSerializer)
|
||||
"ApplicationSerializer"
|
||||
else
|
||||
"ActiveModel::Serializer"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
<% module_namespacing do -%>
|
||||
class <%= class_name %>Serializer < <%= parent_class_name %>
|
||||
attributes <%= attributes_names.map(&:inspect).join(", ") %>
|
||||
<% association_names.each do |attribute| -%>
|
||||
has_one :<%= attribute %>
|
||||
<% end -%>
|
||||
end
|
||||
<% end -%>
|
||||
Reference in New Issue
Block a user