active_model_serializers/test/association_test.rb
2013-05-30 15:25:06 -06:00

593 lines
13 KiB
Ruby

require "test_helper"
class AssociationTest < ActiveModel::TestCase
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 as_json(*)
{ model: "Model" }
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
@hash = {}
@root_hash = {}
@post = Model.new(title: "New Post", body: "Body")
@comment = Model.new(id: 1, external_id: "COMM001", body: "ZOMG A COMMENT")
@post.comments = [ @comment ]
@post.comment = @comment
@comment_serializer_class = def_serializer do
attributes :id, :external_id, :body
end
@post_serializer_class = def_serializer do
attributes :title, :body
end
@post_serializer = @post_serializer_class.new(@post, hash: @root_hash)
end
def include!(key, options={})
@post_serializer.include! key, {
embed: :ids,
include: true,
node: @hash,
serializer: @comment_serializer_class
}.merge(options)
end
def include_bare!(key, options={})
@post_serializer.include! key, {
node: @hash,
serializer: @comment_serializer_class
}.merge(options)
end
class NoDefaults < AssociationTest
def test_include_bang_has_many_associations
include! :comments, value: @post.comments
assert_equal({
comment_ids: [ 1 ]
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_include_bang_with_embed_false
include! :comments, value: @post.comments, embed: false
assert_equal({}, @hash)
assert_equal({}, @root_hash)
end
def test_include_bang_with_embed_ids_include_false
include! :comments, value: @post.comments, embed: :ids, include: false
assert_equal({
comment_ids: [ 1 ]
}, @hash)
assert_equal({}, @root_hash)
end
def test_include_bang_has_one_associations
include! :comment, value: @post.comment
assert_equal({
comment_id: 1
}, @hash)
assert_equal({
comments: [{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }]
}, @root_hash)
end
end
class DefaultsTest < AssociationTest
def test_with_default_has_many
@post_serializer_class.class_eval do
has_many :comments
end
include! :comments
assert_equal({
comment_ids: [ 1 ]
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_one
@post_serializer_class.class_eval do
has_one :comment
end
include! :comment
assert_equal({
comment_id: 1
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_many_with_custom_key
@post_serializer_class.class_eval do
has_many :comments, key: :custom_comments
end
include! :comments
assert_equal({
custom_comments: [ 1 ]
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_one_with_custom_key
@post_serializer_class.class_eval do
has_one :comment, key: :custom_comment_id
end
include! :comment
assert_equal({
custom_comment_id: 1
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_many_with_custom_embed_key
@post_serializer_class.class_eval do
has_many :comments, embed_key: :external_id
end
include! :comments
assert_equal({
comment_ids: [ "COMM001" ]
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_one_with_custom_embed_key
@post_serializer_class.class_eval do
has_one :comment, embed_key: :external_id
end
include! :comment
assert_equal({
comment_id: "COMM001"
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_many_with_custom_key_and_custom_embed_key
@post_serializer_class.class_eval do
has_many :comments, key: :custom_comments, embed_key: :external_id
end
include! :comments
assert_equal({
custom_comments: [ "COMM001" ]
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_one_with_custom_key_and_custom_embed_key
@post_serializer_class.class_eval do
has_one :comment, key: :custom_comment, embed_key: :external_id
end
include! :comment
assert_equal({
custom_comment: "COMM001"
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_embed_objects_for_has_many_associations
@post_serializer_class.class_eval do
has_many :comments, embed: :objects
end
include_bare! :comments
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @hash)
assert_equal({}, @root_hash)
end
def test_embed_ids_for_has_many_associations
@post_serializer_class.class_eval do
has_many :comments, embed: :ids
end
include_bare! :comments
assert_equal({
comment_ids: [ 1 ]
}, @hash)
assert_equal({}, @root_hash)
end
def test_embed_false_for_has_many_associations
@post_serializer_class.class_eval do
has_many :comments, embed: false
end
include_bare! :comments
assert_equal({}, @hash)
assert_equal({}, @root_hash)
end
def test_embed_ids_include_true_for_has_many_associations
@post_serializer_class.class_eval do
has_many :comments, embed: :ids, include: true
end
include_bare! :comments
assert_equal({
comment_ids: [ 1 ]
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_embed_ids_for_has_one_associations
@post_serializer_class.class_eval do
has_one :comment, embed: :ids
end
include_bare! :comment
assert_equal({
comment_id: 1
}, @hash)
assert_equal({}, @root_hash)
end
def test_embed_false_for_has_one_associations
@post_serializer_class.class_eval do
has_one :comment, embed: false
end
include_bare! :comment
assert_equal({}, @hash)
assert_equal({}, @root_hash)
end
def test_embed_ids_include_true_for_has_one_associations
@post_serializer_class.class_eval do
has_one :comment, embed: :ids, include: true
end
include_bare! :comment
assert_equal({
comment_id: 1
}, @hash)
assert_equal({
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_embed_ids_include_true_does_not_serialize_multiple_times
@post.recent_comment = @comment
@post_serializer_class.class_eval do
has_one :comment, embed: :ids, include: true
has_one :recent_comment, embed: :ids, include: true, root: :comments
end
# Count how often the @comment record is serialized.
serialized_times = 0
@comment.class_eval do
define_method :read_attribute_for_serialization, lambda { |name|
serialized_times += 1 if name == :body
super(name)
}
end
include_bare! :comment
include_bare! :recent_comment
assert_equal 1, serialized_times
end
def test_include_with_read_association_id_for_serialization_hook
@post_serializer_class.class_eval do
has_one :comment, embed: :ids, include: true
end
association_name = nil
@post.class_eval do
define_method :read_attribute_for_serialization, lambda { |name|
association_name = name
send(name)
}
define_method :comment_id, lambda {
@attributes[:comment].id
}
end
include_bare! :comment
assert_equal({
comment_id: 1
}, @hash)
end
def test_include_with_read_association_ids_for_serialization_hook
@post_serializer_class.class_eval do
has_many :comments, embed: :ids, include: false
end
association_name = nil
@post.class_eval do
define_method :read_attribute_for_serialization, lambda { |name|
association_name = name
send(name)
}
define_method :comment_ids, lambda {
@attributes[:comments].map(&:id)
}
end
include_bare! :comments
assert_equal({
comment_ids: [1]
}, @hash)
end
end
class RecursiveTest < AssociationTest
class BarSerializer < ActiveModel::Serializer; end
class FooSerializer < ActiveModel::Serializer
root :foos
attributes :id
has_many :bars, serializer: BarSerializer, root: :bars, embed: :ids, include: true
end
class BarSerializer < ActiveModel::Serializer
root :bars
attributes :id
has_many :foos, serializer: FooSerializer, root: :foos, embed: :ids, include: true
end
class Foo < Model
def active_model_serializer; FooSerializer; end
end
class Bar < Model
def active_model_serializer; BarSerializer; end
end
def setup
super
foo = Foo.new(id: 1)
bar = Bar.new(id: 2)
foo.bars = [ bar ]
bar.foos = [ foo ]
collection = [ foo ]
@serializer = collection.active_model_serializer.new(collection, root: :foos)
end
def test_mutual_relation_result
assert_equal({
foos: [{
bar_ids: [ 2 ],
id: 1
}],
bars: [{
foo_ids: [ 1 ],
id: 2
}]
}, @serializer.as_json)
end
def test_mutual_relation_does_not_raise_error
assert_nothing_raised SystemStackError, 'stack level too deep' do
@serializer.as_json
end
end
end
class InclusionTest < AssociationTest
def setup
super
comment_serializer_class = @comment_serializer_class
@post_serializer_class.class_eval do
root :post
embed :ids, include: true
has_many :comments, serializer: comment_serializer_class
end
end
def test_when_it_is_included
post_serializer = @post_serializer_class.new(
@post, include: [:comments]
)
json = post_serializer.as_json
assert_equal({
post: {
title: "New Post",
body: "Body",
comment_ids: [ 1 ]
},
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, json)
end
def test_when_it_is_not_included
post_serializer = @post_serializer_class.new(
@post, include: []
)
json = post_serializer.as_json
assert_equal({
post: {
title: "New Post",
body: "Body",
comment_ids: [ 1 ]
}
}, json)
end
def test_when_it_is_excluded
post_serializer = @post_serializer_class.new(
@post, exclude: [:comments]
)
json = post_serializer.as_json
assert_equal({
post: {
title: "New Post",
body: "Body",
comment_ids: [ 1 ]
}
}, json)
end
def test_when_it_is_not_excluded
post_serializer = @post_serializer_class.new(
@post, exclude: []
)
json = post_serializer.as_json
assert_equal({
post: {
title: "New Post",
body: "Body",
comment_ids: [ 1 ]
},
comments: [
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
]
}, json)
end
end
class StringSerializerOption < AssociationTest
class StringSerializer < ActiveModel::Serializer
attributes :id, :body
end
def test_specifying_serializer_class_as_string
@post_serializer_class.class_eval do
has_many :comments, embed: :objects
end
include_bare! :comments, serializer: "AssociationTest::StringSerializerOption::StringSerializer"
assert_equal({
comments: [
{ id: 1, body: "ZOMG A COMMENT" }
]
}, @hash)
assert_equal({}, @root_hash)
end
end
end