diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index b5b95736c..0009e9c39 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -357,6 +357,9 @@ def associations(include_directive = ActiveModelSerializers.default_include_dire 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) @@ -371,7 +374,12 @@ def as_json(adapter_opts = nil) # 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 79ca7b5ff..daae8bf5f 100644 --- a/lib/active_model_serializers/adapter/attributes.rb +++ b/lib/active_model_serializers/adapter/attributes.rb @@ -1,6 +1,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] @@ -8,6 +13,20 @@ def serializable_hash(options = nil) 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 000000000..f44a242f3 --- /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