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
45 changes: 45 additions & 0 deletions lib/active_model/convertable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module ActiveModel
module Convertable
extend ActiveSupport::Concern

included do
class_attribute :_root_proc, :_key_proc

self._key_proc = ->(original) { original }
self._root_proc = ->(original) { original }
end

module ClassMethods
def camelize_keys!(first_letter = :lower)
self._key_proc = ->(original){ camelize_keys original, first_letter }
self._root_proc = ->(original){ original.to_s.camelize(first_letter) }
end

def convert_keys(&proc)
self._key_proc = proc
end

def camelize_keys(original, first_letter = :lower)
original.each_with_object({}) do |(key,value), hash|
hash.merge!(key.to_s.camelize(first_letter) => (value.is_a?(Hash) ? camelize_keys(value, first_letter) : value))
end
end

def _convert_root(root)
_root_proc.call(root)
end

def _convert_keys(original = {})
_key_proc.call(original)
end
end

def _convert_root(root)
_root_proc.call(root)
end

def _convert_keys(original = {})
_key_proc.call(original)
end
end
end
11 changes: 9 additions & 2 deletions lib/active_model/serializable.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
require 'active_model/convertable'
module ActiveModel
module Serializable
extend ActiveSupport::Concern
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed? ^^^

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really, I can do def self.included if you want?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should just include Convertable, there's no need to use that hook


included do
include Convertable
end

def as_json(options={})
if root = options[:root] || self.root
hash = { root => serializable_object }
hash = { _convert_root(root) => serializable_object }
hash.merge!(serializable_data)
hash
else
Expand All @@ -12,7 +19,7 @@ def as_json(options={})

def serializable_data
if respond_to?(:meta) && meta
{ meta_key => meta }
_convert_keys({ meta_key => meta })
else
{}
end
Expand Down
3 changes: 2 additions & 1 deletion lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def initialize(object, options={})
def root=(root)
@root = root
@root = self.class._root if @root.nil?
@root = self.class.root_name if @root == true || @root.nil?
@root = _convert_root(self.class.root_name) if @root == true || @root.nil?
end

def attributes
Expand Down Expand Up @@ -178,6 +178,7 @@ def serializable_hash(options={})
return nil if object.nil?
hash = attributes
hash.merge! associations
_convert_keys(hash)
end
alias serializable_object serializable_hash
end
Expand Down
8 changes: 8 additions & 0 deletions test/fixtures/poro.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ def profile
class Profile < Model
end

class CamelCase < Model
end

class Post < Model
def comments
@comments ||= [Comment.new(content: 'C1'),
Expand Down Expand Up @@ -62,3 +65,8 @@ class PostSerializer < ActiveModel::Serializer
class CommentSerializer < ActiveModel::Serializer
attributes :content
end

class CamelCaseSerializer < ActiveModel::Serializer
attributes :key_one, :key_two
camelize_keys!
end
62 changes: 62 additions & 0 deletions test/unit/active_model/serializer/convertable_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
require 'test_helper'
def MiniTest.filter_backtrace(bt)
bt
end

module ActiveModel
class Serializer
class CamelCaseLowerTest < ActiveModel::TestCase
def setup
@camel_case = CamelCase.new({ key_one: 'Name 1', key_two: 'Name 2' })
@camel_case_serializer = CamelCaseSerializer.new(@camel_case)
@camel_case_serializer.class_eval do
camelize_keys!
end
end

def test_attributes_definition
assert_equal([:key_one, :key_two],
@camel_case_serializer.class._attributes)
end

def test_convert_keys_using_serializable_hash
assert_equal({
'keyOne' => 'Name 1', 'keyTwo' => 'Name 2'
}, @camel_case_serializer.serializable_hash)
end

def test_convert_keys_using_as_json
assert_equal({
'camelCase' => { 'keyOne' => 'Name 1', 'keyTwo' => 'Name 2' }
}, @camel_case_serializer.as_json)
end
end

class CamelCaseUpperTest < ActiveModel::TestCase
def setup
@camel_case = CamelCase.new({ key_one: 'Name 1', key_two: 'Name 2' })
@camel_case_serializer = CamelCaseSerializer.new(@camel_case)
@camel_case_serializer.class_eval do
camelize_keys! :upper
end
end

def test_attributes_definition
assert_equal([:key_one, :key_two],
@camel_case_serializer.class._attributes)
end

def test_convert_keys_using_serializable_hash
assert_equal({
'KeyOne' => 'Name 1', 'KeyTwo' => 'Name 2'
}, @camel_case_serializer.serializable_hash)
end

def test_convert_keys_using_as_json
assert_equal({
'CamelCase' => { 'KeyOne' => 'Name 1', 'KeyTwo' => 'Name 2' }
}, @camel_case_serializer.as_json)
end
end
end
end