More refactoring:

* Changed associations to be classes
* remove @hash and always use @options[:hash]
* pass serializer options down to child serializers
This commit is contained in:
Yehuda Katz 2012-01-11 15:28:49 -07:00
parent 89103f1e74
commit b22eebf569
2 changed files with 80 additions and 39 deletions

View File

@ -11,13 +11,12 @@ module ActiveModel
def initialize(object, scope, options={}) def initialize(object, scope, options={})
@object, @scope, @options = object, scope, options @object, @scope, @options = object, scope, options
@hash = options[:hash]
end end
def serializable_array def serializable_array
@object.map do |item| @object.map do |item|
if item.respond_to?(:active_model_serializer) && (serializer = item.active_model_serializer) if item.respond_to?(:active_model_serializer) && (serializer = item.active_model_serializer)
serializer.new(item, scope, :hash => @hash) serializer.new(item, scope, @options)
else else
item item
end end
@ -25,12 +24,12 @@ module ActiveModel
end end
def as_json(*args) def as_json(*args)
@hash = {} @options[:hash] = hash = {}
array = serializable_array.map(&:serializable_hash) array = serializable_array.map(&:serializable_hash)
if root = @options[:root] if root = @options[:root]
@hash.merge!(root => array) hash.merge!(root => array)
else else
array array
end end
@ -71,32 +70,71 @@ module ActiveModel
# #
class Serializer class Serializer
module Associations #:nodoc: module Associations #:nodoc:
class Config < Struct.new(:name, :options) #:nodoc: class Config #:nodoc:
def serializer class_attribute :association_name
options[:serializer] class_attribute :options
def self.refine(name, class_options)
current_class = self
Class.new(self) do
singleton_class.class_eval do
define_method(:to_s) do
"(subclass of #{current_class.name})"
end
alias inspect to_s
end
self.association_name = name
self.options = class_options
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def initialize(options={})
super(self.class.association_name, options)
end
RUBY
end
end
self.options = {}
def initialize(name=nil, options={})
@name = name || self.class.association_name
@options = options
end
def option(key)
if @options.key?(key)
@options[key]
elsif self.class.options[key]
self.class.options[key]
end
end
def target_serializer
option(:serializer)
end end
def key def key
options[:key] || name option(:key) || @name
end
def name
option(:name) || @name
end end
def associated_object(serializer) def associated_object(serializer)
options[:value] || serializer.send(name) option(:value) || serializer.send(name)
end end
def with_options(options) protected
config = dup
config.options.merge!(options)
config
end
protected def find_serializable(object, scope, serializer)
if target_serializer
def find_serializable(object, scope, context, options) target_serializer.new(object, scope, serializer.options)
if serializer
serializer.new(object, scope, options)
elsif object.respond_to?(:active_model_serializer) && (ams = object.active_model_serializer) elsif object.respond_to?(:active_model_serializer) && (ams = object.active_model_serializer)
ams.new(object, scope, options) ams.new(object, scope, serializer.options)
else else
object object
end end
@ -108,7 +146,7 @@ module ActiveModel
def serialize(serializer, scope) def serialize(serializer, scope)
associated_object(serializer).map do |item| associated_object(serializer).map do |item|
find_serializable(item, scope, serializer, options).as_json(:root => false) find_serializable(item, scope, serializer).serializable_hash
end end
end end
alias serialize_many serialize alias serialize_many serialize
@ -130,12 +168,12 @@ module ActiveModel
def serialize(serializer, scope) def serialize(serializer, scope)
object = associated_object(serializer) object = associated_object(serializer)
object && find_serializable(object, scope, serializer, options).as_json(:root => false) object && find_serializable(object, scope, serializer).serializable_hash
end end
def serialize_many(serializer, scope) def serialize_many(serializer, scope)
object = associated_object(serializer) object = associated_object(serializer)
value = object && find_serializable(object, scope, serializer, options).as_json(:root => false) value = object && find_serializable(object, scope, serializer).serializable_hash
value ? [value] : [] value ? [value] : []
end end
@ -180,7 +218,8 @@ module ActiveModel
unless method_defined?(attr) unless method_defined?(attr)
class_eval "def #{attr}() object.#{attr} end", __FILE__, __LINE__ class_eval "def #{attr}() object.#{attr} end", __FILE__, __LINE__
end end
klass.new(attr, options)
klass.refine(attr, options)
end end
end end
@ -245,7 +284,9 @@ module ActiveModel
hash.merge key => column.type hash.merge key => column.type
end end
associations = _associations.inject({}) do |hash, association| associations = _associations.inject({}) do |hash, association_class|
association = association_class.new
model_association = klass.reflect_on_association(association.name) model_association = klass.reflect_on_association(association.name)
hash.merge association.key => { model_association.macro => model_association.name } hash.merge association.key => { model_association.macro => model_association.name }
end end
@ -285,11 +326,10 @@ module ActiveModel
end end
end end
attr_reader :object, :scope attr_reader :object, :scope, :options
def initialize(object, scope, options={}) def initialize(object, scope, options={})
@object, @scope, @options = object, scope, options @object, @scope, @options = object, scope, options
@hash = options[:hash]
end end
# Returns a json representation of the serializable # Returns a json representation of the serializable
@ -297,11 +337,11 @@ module ActiveModel
def as_json(options=nil) def as_json(options=nil)
options ||= {} options ||= {}
if root = options.fetch(:root, @options.fetch(:root, _root)) if root = options.fetch(:root, @options.fetch(:root, _root))
@hash = hash = {} @options[:hash] = hash = {}
hash.merge!(root => serializable_hash) hash.merge!(root => serializable_hash)
hash hash
else else
@hash = serializable_hash serializable_hash
end end
end end
@ -309,7 +349,7 @@ module ActiveModel
# object without the root. # object without the root.
def serializable_hash def serializable_hash
if _embed == :ids if _embed == :ids
merge_associations(@hash, plural_associations) if _root_embed merge_associations(@options[:hash], plural_associations) if _root_embed
attributes.merge(association_ids) attributes.merge(association_ids)
elsif _embed == :objects elsif _embed == :objects
attributes.merge(associations) attributes.merge(associations)
@ -327,11 +367,11 @@ module ActiveModel
serializer = options[:serializer] serializer = options[:serializer]
scope = options[:scope] scope = options[:scope]
association = _associations.find do |a| association_class = _associations.find do |a|
a.name == name a.association_name == name
end end
association = association.with_options(options) if association association = association_class.new(options) if association_class
association ||= if value.respond_to?(:to_ary) association ||= if value.respond_to?(:to_ary)
Associations::HasMany.new(name, options) Associations::HasMany.new(name, options)
@ -371,8 +411,8 @@ module ActiveModel
def associations def associations
hash = {} hash = {}
_associations.each do |association| _associations.each do |association_class|
association = association.with_options(:hash => @hash) association = association_class.new
hash[association.key] = association.serialize(self, scope) hash[association.key] = association.serialize(self, scope)
end end
@ -382,8 +422,8 @@ module ActiveModel
def plural_associations def plural_associations
hash = {} hash = {}
_associations.each do |association| _associations.each do |association_class|
association = association.with_options(:hash => @hash) association = association_class.new
hash[association.plural_key] = association.serialize_many(self, scope) hash[association.plural_key] = association.serialize_many(self, scope)
end end
@ -395,7 +435,8 @@ module ActiveModel
def association_ids def association_ids
hash = {} hash = {}
_associations.each do |association| _associations.each do |association_class|
association = association_class.new
hash[association.key] = association.serialize_ids(self, scope) hash[association.key] = association.serialize_ids(self, scope)
end end

View File

@ -737,7 +737,7 @@ class SerializerTest < ActiveModel::TestCase
attributes :id, :name attributes :id, :name
define_method :serializable_hash do define_method :serializable_hash do
hash_object = @hash hash_object = @options[:hash]
super() super()
end end
end end