From 00c54baae374077e5623e597400e338c66ff8c01 Mon Sep 17 00:00:00 2001 From: Kyle Fritz Date: Sun, 30 Mar 2014 11:53:24 -0400 Subject: [PATCH 1/2] Support lowerCamel key format --- README.md | 17 ++++++++++ lib/active_model/array_serializer.rb | 5 +-- lib/active_model/serializer.rb | 31 +++++++++++++++++++ lib/active_model/serializer/associations.rb | 3 +- test/fixtures/poro.rb | 11 +++++++ .../array_serializer/key_format_test.rb | 18 +++++++++++ .../active_model/serializer/config_test.rb | 2 ++ .../serializer/key_format_test.rb | 25 +++++++++++++++ 8 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 test/unit/active_model/array_serializer/key_format_test.rb create mode 100644 test/unit/active_model/serializer/key_format_test.rb diff --git a/README.md b/README.md index 03a0a9b6..1bb0b7a4 100644 --- a/README.md +++ b/README.md @@ -226,6 +226,23 @@ def default_serializer_options end ``` +## Changing the Key Format + +You can specify that serializers use the lower-camel key format at the config, class or instance level. + +```ruby + +ActiveModel::Serializer.setup do |config| + config.key_format = :lower_camel +end + +class BlogLowerCamelSerializer < ActiveModel::Serializer + format_keys :lower_camel +end + +BlogSerializer.new(object, key_format: :lower_camel) +``` + ## Getting the old version If you find that your project is already relying on the old rails to_json diff --git a/lib/active_model/array_serializer.rb b/lib/active_model/array_serializer.rb index 32a382f0..ad5ce346 100644 --- a/lib/active_model/array_serializer.rb +++ b/lib/active_model/array_serializer.rb @@ -20,8 +20,9 @@ module ActiveModel @meta = options[@meta_key] @each_serializer = options[:each_serializer] @resource_name = options[:resource_name] + @key_format = options[:key_format] end - attr_accessor :object, :scope, :root, :meta_key, :meta + attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format def json_key if root.nil? @@ -33,7 +34,7 @@ module ActiveModel def serializer_for(item) serializer_class = @each_serializer || Serializer.serializer_for(item) || DefaultSerializer - serializer_class.new(item, scope: scope) + serializer_class.new(item, scope: scope, key_format: key_format) end def serializable_object diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index a21c2884..a2c832f9 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -38,6 +38,11 @@ end WARN end + def format_keys(format) + @key_format = format + end + attr_reader :key_format + if RUBY_VERSION >= '2.0' def serializer_for(resource) if resource.respond_to?(:to_ary) @@ -110,6 +115,7 @@ end @wrap_in_array = options[:_wrap_in_array] @only = Array(options[:only]) if options[:only] @except = Array(options[:except]) if options[:except] + @key_format = options[:key_format] end attr_accessor :object, :scope, :root, :meta_key, :meta @@ -190,10 +196,35 @@ end end end + def key_format + @key_format || self.class.key_format || CONFIG.key_format + end + + def format_key(key) + if key_format == :lower_camel + key.to_s.camelize(:lower) + else + key + end + end + + def convert_keys(hash) + Hash[hash.map do |k,v| + key = if k.is_a?(Symbol) + format_key(k).to_sym + else + format_key(k) + end + + [key ,v] + end] + end + def serializable_object(options={}) return @wrap_in_array ? [] : nil if @object.nil? hash = attributes hash.merge! associations + hash = convert_keys(hash) if key_format.present? @wrap_in_array ? [hash] : hash end alias_method :serializable_hash, :serializable_object diff --git a/lib/active_model/serializer/associations.rb b/lib/active_model/serializer/associations.rb index d377119d..7f414b9c 100644 --- a/lib/active_model/serializer/associations.rb +++ b/lib/active_model/serializer/associations.rb @@ -15,6 +15,7 @@ module ActiveModel @options = options self.embed = options.fetch(:embed) { CONFIG.embed } @embed_in_root = options.fetch(:embed_in_root) { options.fetch(:include) { CONFIG.embed_in_root } } + @key_format = options.fetch(:key_format) { CONFIG.key_format } @embed_key = options[:embed_key] || :id @key = options[:key] @embedded_key = options[:root] || name @@ -24,7 +25,7 @@ module ActiveModel end attr_reader :name, :embed_ids, :embed_objects - attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options + attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options, :key_format alias embed_ids? embed_ids alias embed_objects? embed_objects alias embed_in_root? embed_in_root diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index a43954b5..6909ef2c 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -35,6 +35,9 @@ end class Comment < Model end +class Blog < Model +end + ### ## Serializers ### @@ -62,3 +65,11 @@ end class CommentSerializer < ActiveModel::Serializer attributes :content end + +class BlogSerializer < ActiveModel::Serializer + attributes :name, :display_name +end + +class BlogLowerCamelSerializer < BlogSerializer + format_keys :lower_camel +end diff --git a/test/unit/active_model/array_serializer/key_format_test.rb b/test/unit/active_model/array_serializer/key_format_test.rb new file mode 100644 index 00000000..6ddd82b8 --- /dev/null +++ b/test/unit/active_model/array_serializer/key_format_test.rb @@ -0,0 +1,18 @@ +require 'test_helper' + +module ActiveModel + class ArraySerializer + class KeyFormatTest < Minitest::Test + def test_array_serializer_pass_options_to_items_serializers + array = [Blog.new({ name: 'Name 1', display_name: 'Display Name 1'}), + Blog.new({ name: 'Name 2', display_name: 'Display Name 2'})] + serializer = ArraySerializer.new(array, key_format: :lower_camel) + + expected = [{ name: 'Name 1', displayName: 'Display Name 1' }, + { name: 'Name 2', displayName: 'Display Name 2' }] + + assert_equal expected, serializer.serializable_array + end + end + end +end diff --git a/test/unit/active_model/serializer/config_test.rb b/test/unit/active_model/serializer/config_test.rb index a7f20976..b297f998 100644 --- a/test/unit/active_model/serializer/config_test.rb +++ b/test/unit/active_model/serializer/config_test.rb @@ -67,6 +67,7 @@ module ActiveModel def test_apply_config_to_associations CONFIG.embed = :ids CONFIG.embed_in_root = true + CONFIG.key_format = :lower_camel association = PostSerializer._associations[:comments] old_association = association.dup @@ -76,6 +77,7 @@ module ActiveModel assert association.embed_ids? assert !association.embed_objects? assert association.embed_in_root + assert_equal :lower_camel, association.key_format ensure PostSerializer._associations[:comments] = old_association CONFIG.clear diff --git a/test/unit/active_model/serializer/key_format_test.rb b/test/unit/active_model/serializer/key_format_test.rb new file mode 100644 index 00000000..aada664a --- /dev/null +++ b/test/unit/active_model/serializer/key_format_test.rb @@ -0,0 +1,25 @@ +require 'test_helper' + +module ActiveModel + class Serializer + class KeyFormatTest < Minitest::Test + def test_lower_camel_format_option + object = Blog.new({ name: 'Name 1', display_name: 'Display Name 1'}) + serializer = BlogSerializer.new(object, key_format: :lower_camel) + + expected = { name: 'Name 1', displayName: 'Display Name 1' } + + assert_equal expected, serializer.serializable_object + end + + def test_lower_camel_format_serializer + object = Blog.new({ name: 'Name 1', display_name: 'Display Name 1'}) + serializer = BlogLowerCamelSerializer.new(object) + + expected = { name: 'Name 1', displayName: 'Display Name 1' } + + assert_equal expected, serializer.serializable_object + end + end + end +end From 76c8de7b9fa62bafacb36d7098ef5860b8424490 Mon Sep 17 00:00:00 2001 From: Kyle Fritz Date: Mon, 14 Apr 2014 13:45:12 -0400 Subject: [PATCH 2/2] root key format --- lib/active_model/array_serializer.rb | 9 +++------ lib/active_model/serializer.rb | 6 ++++-- test/fixtures/poro.rb | 6 +++--- .../action_controller/serialization_test.rb | 16 ++++++++++++++++ .../array_serializer/key_format_test.rb | 4 ++-- .../active_model/serializer/key_format_test.rb | 8 ++++---- 6 files changed, 32 insertions(+), 17 deletions(-) diff --git a/lib/active_model/array_serializer.rb b/lib/active_model/array_serializer.rb index ad5ce346..b3e67aa5 100644 --- a/lib/active_model/array_serializer.rb +++ b/lib/active_model/array_serializer.rb @@ -20,16 +20,13 @@ module ActiveModel @meta = options[@meta_key] @each_serializer = options[:each_serializer] @resource_name = options[:resource_name] - @key_format = options[:key_format] + @key_format = options[:key_format] || options[:each_serializer].try(:key_format) end attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format def json_key - if root.nil? - @resource_name - else - root - end + key = root.nil? ? @resource_name : root + key_format == :lower_camel ? key.camelize(:lower) : key end def serializer_for(item) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index a2c832f9..f0244a6e 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -117,14 +117,16 @@ end @except = Array(options[:except]) if options[:except] @key_format = options[:key_format] end - attr_accessor :object, :scope, :root, :meta_key, :meta + attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format def json_key - if root == true || root.nil? + key = if root == true || root.nil? self.class.root_name else root end + + key_format == :lower_camel ? key.camelize(:lower) : key end def attributes diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index 6909ef2c..a357c24e 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -35,7 +35,7 @@ end class Comment < Model end -class Blog < Model +class WebLog < Model end ### @@ -66,10 +66,10 @@ class CommentSerializer < ActiveModel::Serializer attributes :content end -class BlogSerializer < ActiveModel::Serializer +class WebLogSerializer < ActiveModel::Serializer attributes :name, :display_name end -class BlogLowerCamelSerializer < BlogSerializer +class WebLogLowerCamelSerializer < WebLogSerializer format_keys :lower_camel end diff --git a/test/integration/action_controller/serialization_test.rb b/test/integration/action_controller/serialization_test.rb index 7ffd4c56..9065e211 100644 --- a/test/integration/action_controller/serialization_test.rb +++ b/test/integration/action_controller/serialization_test.rb @@ -194,6 +194,22 @@ module ActionController end end + class LowerCamelArraySerializerTest < ActionController::TestCase + class WebLogController < ActionController::Base + def render_array + render json: [WebLog.new({name: 'Name 1', display_name: 'Display Name 1'}), WebLog.new({name: 'Name 2', display_name: 'Display Name 2'})], each_serializer: WebLogLowerCamelSerializer + end + end + + tests WebLogController + + def test_render_array + get :render_array + assert_equal 'application/json', @response.content_type + assert_equal '{"webLog":[{"name":"Name 1","displayName":"Display Name 1"},{"name":"Name 2","displayName":"Display Name 2"}]}', @response.body + end + end + class ArrayEmbedingSerializerTest < ActionController::TestCase def setup super diff --git a/test/unit/active_model/array_serializer/key_format_test.rb b/test/unit/active_model/array_serializer/key_format_test.rb index 6ddd82b8..4c247bfd 100644 --- a/test/unit/active_model/array_serializer/key_format_test.rb +++ b/test/unit/active_model/array_serializer/key_format_test.rb @@ -4,8 +4,8 @@ module ActiveModel class ArraySerializer class KeyFormatTest < Minitest::Test def test_array_serializer_pass_options_to_items_serializers - array = [Blog.new({ name: 'Name 1', display_name: 'Display Name 1'}), - Blog.new({ name: 'Name 2', display_name: 'Display Name 2'})] + array = [WebLog.new({ name: 'Name 1', display_name: 'Display Name 1'}), + WebLog.new({ name: 'Name 2', display_name: 'Display Name 2'})] serializer = ArraySerializer.new(array, key_format: :lower_camel) expected = [{ name: 'Name 1', displayName: 'Display Name 1' }, diff --git a/test/unit/active_model/serializer/key_format_test.rb b/test/unit/active_model/serializer/key_format_test.rb index aada664a..135866bf 100644 --- a/test/unit/active_model/serializer/key_format_test.rb +++ b/test/unit/active_model/serializer/key_format_test.rb @@ -4,8 +4,8 @@ module ActiveModel class Serializer class KeyFormatTest < Minitest::Test def test_lower_camel_format_option - object = Blog.new({ name: 'Name 1', display_name: 'Display Name 1'}) - serializer = BlogSerializer.new(object, key_format: :lower_camel) + object = WebLog.new({ name: 'Name 1', display_name: 'Display Name 1'}) + serializer = WebLogSerializer.new(object, key_format: :lower_camel) expected = { name: 'Name 1', displayName: 'Display Name 1' } @@ -13,8 +13,8 @@ module ActiveModel end def test_lower_camel_format_serializer - object = Blog.new({ name: 'Name 1', display_name: 'Display Name 1'}) - serializer = BlogLowerCamelSerializer.new(object) + object = WebLog.new({ name: 'Name 1', display_name: 'Display Name 1'}) + serializer = WebLogLowerCamelSerializer.new(object) expected = { name: 'Name 1', displayName: 'Display Name 1' }