From 06fcd34807e5964f7b90d63194fdb2d6494bbaec Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Sun, 19 Nov 2017 23:55:46 -0600 Subject: [PATCH] Follows https://github.com/rails-api/active_model_serializers/pull/2100 --- lib/active_model/serializer.rb | 10 ++- .../adapter/attributes.rb | 19 ++++++ test/adapter/json/fields_test.rb | 63 +++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 test/adapter/json/fields_test.rb diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 04dcf8f0..864eba7b 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -365,6 +365,9 @@ module ActiveModel def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance) adapter_options ||= {} options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options) + if (fieldset = adapter_options[:fieldset]) + options[:fields] = fieldset.fields_for(json_key) + end resource = attributes_hash(adapter_options, options, adapter_instance) relationships = associations_hash(adapter_options, options, adapter_instance) resource.merge(relationships) @@ -379,7 +382,12 @@ module ActiveModel # Used by adapter as resource root. def json_key - root || _type || object.class.model_name.to_s.underscore + root || _type || + begin + object.class.model_name.to_s.underscore + rescue ArgumentError + 'anonymous_object' + end end def read_attribute_for_serialization(attr) diff --git a/lib/active_model_serializers/adapter/attributes.rb b/lib/active_model_serializers/adapter/attributes.rb index c0674e5b..af95797a 100644 --- a/lib/active_model_serializers/adapter/attributes.rb +++ b/lib/active_model_serializers/adapter/attributes.rb @@ -3,6 +3,11 @@ module ActiveModelSerializers module Adapter class Attributes < Base + def initialize(*) + super + instance_options[:fieldset] ||= ActiveModel::Serializer::Fieldset.new(fields_to_fieldset(instance_options.delete(:fields))) + end + def serializable_hash(options = nil) options = serialization_options(options) options[:fields] ||= instance_options[:fields] @@ -10,6 +15,20 @@ module ActiveModelSerializers self.class.transform_key_casing!(serialized_hash, instance_options) end + + def fields_to_fieldset(fields) + return fields if fields.nil? + resource_fields = [] + relationship_fields = {} + fields.each do |field| + case field + when Symbol, String then resource_fields << field + when Hash then relationship_fields.merge!(field) + else fail ArgumentError, "Unknown conversion of fields to fieldset: '#{field.inspect}' in '#{fields.inspect}'" + end + end + relationship_fields.merge(serializer.json_key.to_sym => resource_fields) + end end end end diff --git a/test/adapter/json/fields_test.rb b/test/adapter/json/fields_test.rb new file mode 100644 index 00000000..f44a242f --- /dev/null +++ b/test/adapter/json/fields_test.rb @@ -0,0 +1,63 @@ +require 'test_helper' + +module ActiveModelSerializers + module Adapter + class Json + class FieldsTest < ActiveSupport::TestCase + class Post < ::Model + attributes :title, :body + associations :author, :comments + end + class Author < ::Model + attributes :name, :birthday + end + class Comment < ::Model + attributes :title, :body + associations :author, :post + end + + class PostSerializer < ActiveModel::Serializer + type 'posts' + attributes :title, :body + belongs_to :author + has_many :comments + end + + class AuthorSerializer < ActiveModel::Serializer + attributes :name, :birthday + end + + class CommentSerializer < ActiveModel::Serializer + type 'comments' + attributes :title, :body + belongs_to :author + end + + def setup + @author = Author.new(id: 1, name: 'Lucas', birthday: '10.01.1990') + @comment1 = Comment.new(id: 7, body: 'cool', author: @author) + @comment2 = Comment.new(id: 12, body: 'awesome', author: @author) + @post = Post.new(id: 1337, title: 'Title 1', body: 'Body 1', + author: @author, comments: [@comment1, @comment2]) + @comment1.post = @post + @comment2.post = @post + end + + def test_fields_attributes + fields = [:title] + hash = serializable(@post, adapter: :json, fields: fields, include: []).serializable_hash + expected = { title: 'Title 1' } + assert_equal(expected, hash[:posts]) + end + + def test_fields_included + fields = [:title, { comments: [:body] }] + hash = serializable(@post, adapter: :json, include: [:comments], fields: fields).serializable_hash + expected = [{ body: @comment1.body }, { body: @comment2.body }] + + assert_equal(expected, hash[:posts][:comments]) + end + end + end + end +end