Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ language: ruby
rvm:
- 1.9.3
- 2.0.0
- jruby-19mode
- rbx-19mode
- ruby-head
- jruby
- rbx
gemfile:
- Gemfile
- Gemfile.rails3
- Gemfile.edge
matrix:
allow_failures:
- rvm: jruby
- rvm: rbx
- gemfile: Gemfile.edge
fast_finish: true
notifications:
email: false
campfire:
Expand Down
4 changes: 3 additions & 1 deletion lib/active_model/serializable.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module ActiveModel
module Serializable
def as_json(options={})
if root = options.fetch(:root, json_key)
root = options.fetch(:root, json_key)
root = apply_conversion(root) if @convert_type
if root
hash = { root => serializable_object }
hash.merge!(serializable_data)
hash
Expand Down
37 changes: 28 additions & 9 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
module ActiveModel
class Serializer
include Serializable

class_attribute :_root
@mutex = Mutex.new

class << self
Expand Down Expand Up @@ -59,7 +59,7 @@ def serializer_for(resource)
end
end

attr_accessor :_root, :_attributes, :_associations
attr_accessor :_attributes, :_associations
alias root _root=
alias root= _root=

Expand Down Expand Up @@ -101,14 +101,15 @@ def associate(klass, *attrs)
end

def initialize(object, options={})
@object = object
@scope = options[:scope]
@root = options.fetch(:root, self.class._root)
@meta_key = options[:meta_key] || :meta
@meta = options[@meta_key]
@object = object
@scope = options[:scope]
@root = options.fetch(:root, self.class._root)
@meta_key = options[:meta_key] || :meta
@meta = options[@meta_key]
@convert_type = options[:convert_type]
@options = options.reject{|k,v| [:scope, :root, :meta_key, :meta].include?(k) }
end
attr_accessor :object, :scope, :meta_key, :meta, :root, :options
attr_accessor :object, :scope, :meta_key, :meta, :root, :convert_type, :options

def json_key
if root == true || root.nil?
Expand Down Expand Up @@ -172,8 +173,26 @@ def serialize_ids(association)
def serializable_hash(options={})
return nil if object.nil?
hash = attributes
hash.merge! associations
convert_keys hash.merge!(associations)
end
alias_method :serializable_object, :serializable_hash

def convert_keys(hash)
hash.inject({}) { |h, (k, v)| h[apply_conversion(k)] = v; h }
end

def apply_conversion(key)
return key.to_s.camelize(:lower) if convert_type == 'camelcase'
return key.to_s.upcase if convert_type == 'upcase'
key
end

def camelize_keys!
@convert_type = "camelcase"
end

def upcase_keys!
@convert_type = "upcase"
end
end
end
5 changes: 3 additions & 2 deletions lib/active_model/serializer/associations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ def embed=(embed)
@embed_objects = embed == :object || embed == :objects
end

def build_serializer(object, options = {})
@serializer_class.new(object, options.merge(@options))
def build_serializer(object, convert_type = nil)
@serializer_class ||= Serializer.serializer_for(object) || DefaultSerializer
@serializer_class.new(object, @options.merge(:convert_type => convert_type))
end

private
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/poro.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def description
end

class PostSerializer < ActiveModel::Serializer
attributes :title, :body
attributes :title, :body, :created_at, :updated_at

has_many :comments
end
Expand Down
38 changes: 38 additions & 0 deletions test/unit/active_model/serializer/attributes_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,43 @@ def test_attributes_serialization_using_as_json
}, @profile_serializer.as_json)
end
end

class HashKeyTest < ActiveModel::TestCase
def setup
@post = Post.new({ title: 'test', body: 'lorem ipsum', created_at: Time.now, updated_at: Time.now })
@post_serializer = PostSerializer.new(@post)
end

def test_attributes_serialization_using_camelcase_key_conversion
@post_serializer.convert_type = 'camelcase'
assert_match({
'title' => 'test', 'body' => 'lorem ipsum', 'createdAt' => Time.now, 'updatedAt' => Time.now, 'comments' => [{ 'content' => 'C1'}, { 'content' => 'C2'}]
}.to_s, @post_serializer.serializable_hash.to_s)
end

def test_attributes_serialization_using_upcase_key_conversion
@post_serializer.convert_type = 'upcase'
assert_match({
'TITLE' => 'test', 'BODY' => 'lorem ipsum', 'CREATED_AT' => Time.now, 'UPDATED_AT' => Time.now, 'COMMENTS' => [{'CONTENT' => 'C1'}, { 'CONTENT' => 'C2'}]
}.to_s, @post_serializer.serializable_hash.to_s)
end
end

class HelpersTest < ActiveModel::TestCase
def setup
@post = Post.new({ title: 'test', body: 'lorem ipsum', created_at: Time.now, updated_at: Time.now })
@post_serializer = PostSerializer.new(@post)
end

def test_attributes_serialization_using_camelize_keys_helper
@post_serializer.camelize_keys!
assert_equal("camelcase", @post_serializer.convert_type)
end

def test_attributes_serialization_using_upcase_keys_helper
@post_serializer.upcase_keys!
assert_equal("upcase", @post_serializer.convert_type)
end
end
end
end
2 changes: 1 addition & 1 deletion test/unit/active_model/serializer/filter_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def teardown

def test_filtered_associations_serialization
assert_equal({
'post' => { title: 'Title 1' }
'post' => { title: 'Title 1', created_at: nil, updated_at: nil }
}, @post_serializer.as_json)
end
end
Expand Down
26 changes: 13 additions & 13 deletions test/unit/active_model/serializer/has_many_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ def test_associations_embedding_ids_serialization_using_serializable_hash
@association.embed = :ids

assert_equal({
title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }
title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, 'comment_ids' => @post.comments.map { |c| c.object_id }
}, @post_serializer.serializable_hash)
end

def test_associations_embedding_ids_serialization_using_as_json
@association.embed = :ids

assert_equal({
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } }
'post' => { title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, 'comment_ids' => @post.comments.map { |c| c.object_id } }
}, @post_serializer.as_json)
end

Expand All @@ -42,23 +42,23 @@ def test_associations_embedding_ids_serialization_using_serializable_hash_and_ke
@association.key = 'key'

assert_equal({
title: 'Title 1', body: 'Body 1', 'key' => @post.comments.map { |c| c.object_id }
title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, 'key' => @post.comments.map { |c| c.object_id }
}, @post_serializer.serializable_hash)
end

def test_associations_embedding_objects_serialization_using_serializable_hash
@association.embed = :objects

assert_equal({
title: 'Title 1', body: 'Body 1', comments: [{ content: 'C1' }, { content: 'C2' }]
title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, comments: [{ content: 'C1' }, { content: 'C2' }]
}, @post_serializer.serializable_hash)
end

def test_associations_embedding_objects_serialization_using_as_json
@association.embed = :objects

assert_equal({
'post' => { title: 'Title 1', body: 'Body 1', comments: [{ content: 'C1' }, { content: 'C2' }] }
'post' => { title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, comments: [{ content: 'C1' }, { content: 'C2' }] }
}, @post_serializer.as_json)
end

Expand All @@ -71,7 +71,7 @@ def comments
end

assert_equal({
'post' => { title: 'Title 1', body: 'Body 1', comments: [nil] }
'post' => { title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, comments: [nil] }
}, @post_serializer.as_json)
end

Expand All @@ -80,7 +80,7 @@ def test_associations_embedding_objects_serialization_using_serializable_hash_an
@association.embedded_key = 'root'

assert_equal({
title: 'Title 1', body: 'Body 1', 'root' => [{ content: 'C1' }, { content: 'C2' }]
title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, 'root' => [{ content: 'C1' }, { content: 'C2' }]
}, @post_serializer.serializable_hash)
end

Expand All @@ -89,7 +89,7 @@ def test_associations_embedding_ids_including_objects_serialization_using_serial
@association.embed_in_root = true

assert_equal({
title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }
title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, 'comment_ids' => @post.comments.map { |c| c.object_id }
}, @post_serializer.serializable_hash)
end

Expand All @@ -98,7 +98,7 @@ def test_associations_embedding_ids_including_objects_serialization_using_as_jso
@association.embed_in_root = true

assert_equal({
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
'post' => { title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, 'comment_ids' => @post.comments.map { |c| c.object_id } },
comments: [{ content: 'C1' }, { content: 'C2' }]
}, @post_serializer.as_json)
end
Expand All @@ -108,7 +108,7 @@ def test_associations_embedding_nothing_including_objects_serialization_using_as
@association.embed_in_root = true

assert_equal({
'post' => { title: 'Title 1', body: 'Body 1' },
'post' => { title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil },
comments: [{ content: 'C1' }, { content: 'C2' }]
}, @post_serializer.as_json)
end
Expand All @@ -125,7 +125,7 @@ def content
end

assert_equal({
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
'post' => { title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, 'comment_ids' => @post.comments.map { |c| c.object_id } },
comments: [{ content: 'fake' }, { content: 'fake' }]
}, @post_serializer.as_json)
end
Expand All @@ -140,7 +140,7 @@ def serializable_object
end

assert_equal({
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
'post' => { title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, 'comment_ids' => @post.comments.map { |c| c.object_id } },
comments: { my_content: ['fake'] }
}, @post_serializer.as_json)
end
Expand All @@ -153,7 +153,7 @@ def serializable_object
end

assert_equal({
'post' => { title: 'Title 1', body: 'Body 1', comments: { my_content: ['fake'] } }
'post' => { title: 'Title 1', body: 'Body 1', created_at: nil, updated_at: nil, comments: { my_content: ['fake'] } }
}, @post_serializer.as_json)
end
end
Expand Down
13 changes: 11 additions & 2 deletions test/unit/active_model/serializer/root_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class RootAsOptionTest < ActiveModel::TestCase
def setup
@old_root = ProfileSerializer._root
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
@serializer = ProfileSerializer.new(@profile, root: :initialize)
@serializer = ProfileSerializer.new(@profile, root: :new_posts)
ProfileSerializer._root = true
end

Expand All @@ -22,12 +22,21 @@ def test_root_is_not_displayed_using_serializable_hash

def test_root_using_as_json
assert_equal({
initialize: {
new_posts: {
name: 'Name 1', description: 'Description 1'
}
}, @serializer.as_json)
end

def test_root_applied_conversion_using_as_json
@serializer.camelize_keys!
assert_equal({
'newPosts' => {
'name' => 'Name 1', 'description' => 'Description 1'
}
}, @serializer.as_json)
end

def test_root_from_serializer_name
@serializer = ProfileSerializer.new(@profile)

Expand Down