diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c638d73..2d257f31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,14 @@ Breaking changes: Features: +- [#2327](https://github.com/rails-api/active_model_serializers/pull/2327) Add support for Ruby 2.6 on Travis CI (@wasifhossain) + Fixes: + - [#2319](https://github.com/rails-api/active_model_serializers/pull/2319) Fixes #2316. (@kylekeesling) - - Fix Rails 6.0 deprication warnings - - update test fixture schema to use `timestamps` instead of `timestamp` + - Fix Rails 6.0 deprication warnings + - update test fixture schema to use `timestamps` instead of `timestamp` +- [#2223](https://github.com/rails-api/active_model_serializers/pull/2223) Support Fieldset in Attributes/JSON adapters documented in [docs/general/fields.md](https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/fields.md) that worked partially before (@bf4) Misc: 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..3372e2be 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,22 @@ module ActiveModelSerializers self.class.transform_key_casing!(serialized_hash, instance_options) end + + private + + 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..5e1f570a --- /dev/null +++ b/test/adapter/json/fields_test.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +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 'post' + attributes :title, :body + belongs_to :author + has_many :comments + end + + class AuthorSerializer < ActiveModel::Serializer + attributes :name, :birthday + end + + class CommentSerializer < ActiveModel::Serializer + type 'comment' + 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[:post]) + 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[:post][:comments]) + end + end + end + end +end diff --git a/test/support/ruby_2_6_rails_4_2_patch.rb b/test/support/ruby_2_6_rails_4_2_patch.rb index 9e250339..768e9430 100644 --- a/test/support/ruby_2_6_rails_4_2_patch.rb +++ b/test/support/ruby_2_6_rails_4_2_patch.rb @@ -13,6 +13,12 @@ if RUBY_VERSION >= '2.6.0' end end else - puts 'Monkeypatch for ActionController::TestResponse no longer needed' + msg = 'Monkeypatch for ActionController::TestResponse not needed for '\ + 'Rails 5+. We can drop this patch once we drop support for Rails < 5. '\ + "Current Rails version: #{ENV['RAILS_VERSION']}" + + puts + puts "\033[33m **** #{msg} **** \033[0m" + puts end end