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
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,35 @@ def default_serializer_options
end
```


## Camelization

The `camelize` option takes either the value `:lower` which yields `camelCase`
and `true` that yields `CamelCase` keys and roots.

It is possible to configure camelization of keys and roots in two different ways.

#### 1. Enable camelization globally for all, or per class

In an initializer:

```ruby
ActiveSupport.on_load(:active_model_serializers) do
# Enable camelization
ActiveModel::Serializer.camelize = true
end
```

#### 2. Subclass the serializer, and specify using it

```ruby
class MySerializer < ActiveModel::Serializer
self.camelize = :lower
# OR
camelize :lower
end
```

## Getting the old version

If you find that your project is already relying on the old rails to_json
Expand Down
39 changes: 34 additions & 5 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def to_s
end
end

class_attribute :_camelize

class_attribute :_attributes
self._attributes = {}

Expand Down Expand Up @@ -94,7 +96,7 @@ def attributes(*attrs)
end

def attribute(attr, options={})
self._attributes = _attributes.merge(attr.is_a?(Hash) ? attr : {attr => options[:key] || attr.to_s.gsub(/\?$/, '').to_sym})
self._attributes = _attributes.merge(attr.is_a?(Hash) ? attr : {attr => options[:key] || camelize_value(attr.to_s.gsub(/\?$/, ''))})

attr = attr.keys[0] if attr.is_a? Hash

Expand Down Expand Up @@ -257,6 +259,17 @@ def root(name)
end
alias_method :root=, :root

# Sets camelization for attribute names
#
# :lower = camelCaseLikeThis
# true = CamelCaseLikeThis
# false = dont_camel_case_anything
#
def camelize(camelize)
self._camelize = camelize
end
alias_method :camelize=, :camelize

# Used internally to create a new serializer object based on controller
# settings and options for a given resource. These settings are typically
# set during the request lifecycle or by the controller class, and should
Expand Down Expand Up @@ -289,6 +302,17 @@ def build_json(controller, resource, options)

serializer.new(resource, options)
end

def camelize_value(value)
return nil unless value
if self._camelize.to_s == 'lower'
value.to_s.camelize(:lower)
elsif self._camelize
value.to_s.camelize
else
value.to_s
end.to_sym
end
end

attr_reader :object, :options
Expand All @@ -308,12 +332,13 @@ def root_name
return false if self._root == false

class_name = self.class.name.demodulize.underscore.sub(/_serializer$/, '').to_sym unless self.class.name.blank?

if self._root == true
class_name = if self._root == true
class_name
else
self._root || class_name
end

camelize_value class_name
end

def url_options
Expand Down Expand Up @@ -382,15 +407,15 @@ def include!(name, options={})
association = association_class.new(name, options, self.options)

if association.embed_ids?
node[association.key] = association.serialize_ids
node[camelize_value(association.key)] = association.serialize_ids

if association.embed_in_root? && hash.nil?
raise IncludeError.new(self.class, association.name)
elsif association.embed_in_root? && association.embeddable?
merge_association hash, association.root, association.serializables, unique_values
end
elsif association.embed_objects?
node[association.key] = association.serialize
node[camelize_value(association.key)] = association.serialize
end
end

Expand Down Expand Up @@ -447,6 +472,10 @@ def instrument(name, payload = {}, &block)
ActiveSupport::Notifications.instrument(event_name, payload, &block)
end

def camelize_value(value)
self.class.camelize_value value
end

private

def default_embed_options
Expand Down
42 changes: 27 additions & 15 deletions lib/active_model/serializer/associations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,30 @@ def initialize(name, options={}, serializer_options={})
alias embed_in_root? embed_in_root

def key
if key = options[:key]

key = if key = options[:key]
key
elsif use_id_key?
id_key
else
name
end

camelize_value key
end

private

attr_reader :embed_key, :serializer_class, :options, :serializer_options

def camelize_value(value)
if serializer_class && serializer_class.respond_to?(:camelize_value)
return serializer_class.camelize_value value
end

ActiveModel::Serializer.camelize_value value
end

def find_serializable(object)
if serializer_class
serializer_class.new(object, serializer_options)
Expand All @@ -73,11 +84,11 @@ def find_serializable(object)

class HasMany < Association #:nodoc:
def root
options[:root] || name
camelize_value options[:root] || name
end

def id_key
"#{name.to_s.singularize}_ids".to_sym
camelize_value "#{name.to_s.singularize}_ids".to_sym
end

def serializables
Expand Down Expand Up @@ -111,17 +122,19 @@ def initialize(name, options={}, serializer_options={})
end

def root
if root = options[:root]
rootname = if root = options[:root]
root
elsif polymorphic?
object.class.to_s.pluralize.demodulize.underscore.to_sym
else
name.to_s.pluralize.to_sym
end

camelize_value rootname
end

def id_key
"#{name}_id".to_sym
camelize_value "#{name}_id".to_sym
end

def embeddable?
Expand All @@ -137,7 +150,7 @@ def serialize
if object
if polymorphic?
{
:type => polymorphic_key,
camelize_value("type").to_sym => polymorphic_key,
polymorphic_key => find_serializable(object).serializable_hash
}
else
Expand All @@ -149,17 +162,16 @@ def serialize
def serialize_ids
if object
serializer = find_serializable(object)
id =
if serializer.respond_to?(embed_key)
serializer.send(embed_key)
else
object.read_attribute_for_serialization(embed_key)
end
id = if serializer.respond_to?(embed_key)
serializer.send(embed_key)
else
object.read_attribute_for_serialization(embed_key)
end

if polymorphic?
{
type: polymorphic_key,
id: id
camelize_value("type").to_sym => polymorphic_key,
camelize_value("id").to_sym => id
}
else
id
Expand All @@ -177,7 +189,7 @@ def use_id_key?
end

def polymorphic_key
object.class.to_s.demodulize.underscore.to_sym
camelize_value object.class.to_s.demodulize.underscore.to_sym
end
end
end
Expand Down
1 change: 0 additions & 1 deletion lib/active_model_serializers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ def active_model_serializer

Array.send(:include, ActiveModel::ArraySerializerSupport)
Set.send(:include, ActiveModel::ArraySerializerSupport)

{
active_record: 'ActiveRecord::Relation',
mongoid: 'Mongoid::Criteria'
Expand Down
57 changes: 57 additions & 0 deletions test/serializer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,63 @@ def test_custom_root
assert_equal({ my_blog: { author: nil } }, serializer.new(blog, scope: user).as_json)
end

def test_camelization
camel = Camel.new
serializer = Class.new(ActiveModel::Serializer) do
camelize true
root :camel_upper
attributes :first_name, :last_name
end

assert_equal({
CamelUpper: {
FirstName: "Camel",
LastName: "Case",
}
}, serializer.new(camel).as_json)
end

def test_camelization_lower
camel = Camel.new
serializer = Class.new(ActiveModel::Serializer) do
camelize :lower
root :camel_lower
attributes :first_name, :last_name
end

assert_equal({
camelLower: {
firstName: "Camel",
lastName: "Case",
}
}, serializer.new(camel).as_json)
end

def test_camelization_global_config
begin
ActiveSupport.on_load(:active_model_serializers) do
self.camelize = :lower
end

camel = Camel.new
serializer = Class.new(ActiveModel::Serializer) do
root :not_camel
attributes :first_name, :last_name
end

assert_equal({
notCamel: {
firstName: "Camel",
lastName: "Case"
}
}, serializer.new(camel).as_json)
ensure
ActiveSupport.on_load(:active_model_serializers) do
self.camelize = false
end
end
end

def test_nil_root_object
user = User.new
blog = nil
Expand Down
10 changes: 10 additions & 0 deletions test/test_fakes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ class BlogWithRootSerializer < BlogSerializer
root true
end

class Camel < Model

def initialize(attributes = {})
attributes.reverse_merge!(first_name: "Camel", last_name: 'Case')
super(attributes)
end

attr_accessor :first_name, :last_name
end

class CustomPostSerializer < ActiveModel::Serializer
attributes :title
end
Expand Down