Skip to content

Provide a clear way to include nested associations and fields #1849

Open
@iMacTia

Description

@iMacTia

The Situation

I encourage to have a read to #1333 and #1845.

Let's assume we have the current serializers:

class BlogSerializer < ActiveModel::Serializer
  attributes :id
  attribute :name, key: :title

  has_many :posts
end

class PostSerializer < ActiveModel::Serializer
  attributes :id, :title

  has_one :author
  has_one :category
end

class AuthorSerializer < ActiveModel::Serializer
  attributes :id, :name

  has_one :address 
end

class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name
end

The issue

The only way to specify nested associations inclusion, at the moment, is through the controller's render include option, as shown in the current examples:

# blogs_controller.rb
render json: @blog, include: 'posts.category, posts.author.address', fields: { posts: { category: [:name], author: [:id, :name] } }

# posts_controller.rb
render json: @posts, include: 'category, author.address', fields: { category: [:name], author: [:id, :name] }

The issue is that in this case (I admit is probably a stupid example, but stay with me), when rendering a post, we always want to render also its category name, its author attributes (except for the bio) and its author address.
(@bf4, I would like to specify the fields for author's address as well, but I'm not sure about how to do it in the controller's include.)

The proposed solution

The same result could be achieved without filling controller's with common serialisation logics, moving them into serialisers. For example, the above issue could have a more elegant solution like:

class BlogSerializer < ActiveModel::Serializer
  attributes :id
  attribute :name, key: :title

  has_many :posts, include: :all
end

class PostSerializer < ActiveModel::Serializer
  attributes :id, :title

  has_one :author, exclude: :bio
  has_one :category, include: :name
end

class AuthorSerializer < ActiveModel::Serializer
  attributes :id, :name, :bio

  has_one :address, include: :all
end

class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name
end

# blogs_controller.rb
render json: @blog

# posts_controller.rb
render json: @posts

To be decided

We'll probably need some team discussion together with @bf4 and @NullVoxPopuli
Open questions:

  1. When should include be taken into consideration? Should we use only the ones in the class we're using to serialise? Does the above example make sense or should the Author's and Post's includes be ignored when serialising the Blog because they are on a deeper level?
  2. Should we have some instance-level options as suggested by @tommiller1 here?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions