Provide a schema for a serializer

This commit is contained in:
Yehuda Katz 2011-12-07 11:56:27 -08:00
parent 4efb1f33ab
commit 0f4b61fbcf
2 changed files with 115 additions and 0 deletions

View File

@ -158,6 +158,58 @@ module ActiveModel
associate(Associations::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 :as is used:
#
# class PostsSerializer < ActiveModel::Serializer
# has_many :my_posts, :as => :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.
def schema
klass = model_class
columns = klass.columns_hash
attrs = _attributes.inject({}) do |hash, name|
column = columns[name]
hash.merge name => column[:type]
end
associations = _associations.inject({}) do |hash, association|
model_association = klass.reflect_on_association(association.key)
hash.merge association.key => { model_association.macro => model_association.name }
end
{ :attributes => attrs, :associations => associations }
end
# The model class associated with this serializer.
def model_class
name.sub(/Serializer$/, '')
end
# Define how associations should be embedded.
#
# embed :objects # Embed associations as full objects

View File

@ -508,4 +508,67 @@ class SerializerTest < ActiveModel::TestCase
}
}, serializer.as_json)
end
def setup_model
Class.new do
class << self
def columns_hash
{ :name => { :type => :string }, :age => { :type => :integer } }
end
def reflect_on_association(name)
case name
when :posts
Struct.new(:macro, :name).new(:has_many, :posts)
when :parent
Struct.new(:macro, :name).new(:belongs_to, :parent)
end
end
end
end
end
def test_schema
model = setup_model
serializer = Class.new(ActiveModel::Serializer) do
class << self; self; end.class_eval do
define_method(:model_class) do model end
end
attributes :name, :age
has_many :posts, :serializer => Class.new
has_one :parent, :serializer => Class.new
end
assert_equal serializer.schema, {
:attributes => { :name => :string, :age => :integer },
:associations => {
:posts => { :has_many => :posts },
:parent => { :belongs_to => :parent }
}
}
end
def test_schema_with_as
model = setup_model
serializer = Class.new(ActiveModel::Serializer) do
class << self; self; end.class_eval do
define_method(:model_class) do model end
end
attributes :name, :age
has_many :my_posts, :as => :posts, :serializer => Class.new
has_one :my_parent, :as => :parent, :serializer => Class.new
end
assert_equal serializer.schema, {
:attributes => { :name => :string, :age => :integer },
:associations => {
:my_posts => { :has_many => :posts },
:my_parent => { :belongs_to => :parent }
}
}
end
end