Merge pull request #602 from JordanFaust/add-dsl-for-assocations

Add DSL for associations
This commit is contained in:
Steve Klabnik 2014-08-23 16:51:53 -04:00
commit e7dbea383b
2 changed files with 103 additions and 1 deletions

View File

@ -2,16 +2,18 @@ module ActiveModel
class Serializer
class << self
attr_accessor :_attributes
attr_accessor :_associations
end
def self.inherited(base)
base._attributes = []
base._associations = {}
end
def self.attributes(*attrs)
@_attributes.concat attrs
attrs.each do |attr|
define_method attr do
object.read_attribute_for_serialization(attr)
@ -19,6 +21,41 @@ module ActiveModel
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 self.has_many(*attrs)
associate(:has_many, 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 self.belongs_to(*attrs)
associate(:belongs_to, attrs)
end
def self.associate(type, 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
self._associations[attr] = {type: type, options: options}
end
end
if RUBY_VERSION >= '2.0'
def self.serializer_for(resource)
if resource.respond_to?(:to_ary)

View File

@ -0,0 +1,65 @@
require 'test_helper'
module ActiveModel
class Serializer
class AssocationsTest < Minitest::Test
def def_serializer(&block)
Class.new(ActiveModel::Serializer, &block)
end
class Model
def initialize(hash={})
@attributes = hash
end
def read_attribute_for_serialization(name)
@attributes[name]
end
def method_missing(meth, *args)
if meth.to_s =~ /^(.*)=$/
@attributes[$1.to_sym] = args[0]
elsif @attributes.key?(meth)
@attributes[meth]
else
super
end
end
end
def setup
@post = Model.new({ title: 'New Post', body: 'Body' })
@comment = Model.new({ id: 1, body: 'ZOMG A COMMENT' })
@post.comments = [@comment]
@comment.post = @post
@post_serializer_class = def_serializer do
attributes :title, :body
end
@comment_serializer_class = def_serializer do
attributes :id, :body
end
@post_serializer = @post_serializer_class.new(@post)
@comment_serializer = @comment_serializer_class.new(@comment)
end
def test_has_many
@post_serializer_class.class_eval do
has_many :comments
end
assert_equal({comments: {type: :has_many, options: {}}}, @post_serializer.class._associations)
end
def test_has_one
@comment_serializer_class.class_eval do
belongs_to :post
end
assert_equal({post: {type: :belongs_to, options: {}}}, @comment_serializer.class._associations)
end
end
end
end