Skip to content

Nested serializers/attributes #1190

Closed
Closed
@beauby

Description

tl;dr

We need better serializer lookup in order to handle namespaces, which brings the opportunity to handle nested serializers, and introduce a friendly syntax to declare them.


As you may have noticed, there is currently some work being done on nested serialization. Different needs have been identified:

  1. nesting some or all of the relationships (this is taken care of by Add support for wildcards in nested includes #1158 and Support nested associations for Json and Attributes adapters + Refactor Attributes adapter #1127) via the include adapter option (which allows to specify a potentially infinite (via wildcards) inclusion tree)
  2. nesting some or all of the relationships, and contextually (depending on the serializer) choosing which attributes to serialize (which is taken care of by Add support for nested serializers. #1157, although not currently perfect: specifying a nested serializer forces you to redundantly specify the relationships in the include adapter option, unless you set it to **, in which case only the nested serializers are used)
  3. conditionally include/exclude attributes from a serializer (for instance depending on some authorization primitive), which is being discussed in Attribute filtering for 0.10.x #1141

I think the state of 1. is satisfying.
For 2., we could either extend the include option to handle attributes as well, but this would lead to implicitly defining nested serializers, which is IMO more confusing than actually defining nested serializers (as in #1157). With #1157, nesting serializers works as follows:

PostSerializer < ActiveModel::Serializer
  attributes :title, :body

  belongs_to :author
  AuthorSerializer < ActiveModel::Serializer
    attributes :name

  has_many :comments
  CommentSerializer < ActiveModel::Serializer
    attributes :body, :date
    belongs_to :author # This would be serialized by PostSerializer::AuthorSerializer, unless we define a PostSerializer::CommentSerializer::AuthorSerializer
  end
end

I would be in favor of introducing the following syntax:

PostSerializer < ActiveModel::Serializer
  attributes :title, :body

  belongs_to :author do
    attributes :name
  end

  has_many :comments do
    attributes :body, :date
    belongs_to :author # This would be serialized by PostSerializer::AuthorSerializer, unless we define a PostSerializer::CommentSerializer::AuthorSerializer
  end
end

in conjunction with a default behavior of either including all nested relationships, or at least all nested relationships for which a nested serializer has been provided.

For 3., I think we should either have something like

attribute :secret_stuff, include_if: { object == current_user || current_user.admin? }

or something more like 0.8.x

def include_attributes(included) # I purposely did not use "filter" because it has a specific sense in the scope of JSON API
  if current_user.admin?
     included
  else
     included.except([:secret_stuff1, :secret_stuff2])
  end
end

or maybe both.

Questions? Suggestions? PRs?

UPDATE:
#1225 brings support for nested serializers (and automatically uses serializers in the same namespace as the resource)
#1226 brings support for the block syntax

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions