Sitelet https://github.com/jsonapi-serializer/jsonapi-serializer/issues/218
Skip to content

feature: introduction to optional attributes #218

Description

@rkwap

Suppose we have to use ArticleSerializer to serve article data on multiple endpoints.

Let's assume these attributes to the serializer:

attributes :title, :slug, :description, :is_popular, :content, :collaborators, :tags
and some more...

Since we don't use all of those attributes in all actions, eg. in #index, we will not query for tags or serve the content unnecessarily.
similarly, is_popular will be something that is calculated in a query and we would want that to work that endpoint only.

So, to resolve this currently, we majorly have 2 solutions.

1. Inherited serializers for specific attributes.

BasicArticleSerializer -> attributes :title, :slug, :description

ArticleContentSerializer < BasicArticleSerializer -> attributes :content, :collaborators, :tags

PopularArticlesSerializer < BasicArticleSerializer -> attribute :is_popular

2. Use if conditions

ArticleSerializer

attributes :title, :slug, :description

attribute :popular, if: proc { |_, opt| opt[:with_popular?].present? } do |obj|
  ...
end

attribute :content, if: proc { |_, opt| opt[:with_content?].present? } do |obj|
  ...
end

attribute :collaborators, if: proc { |_, opt| opt[:with_collaborators?].present? } do |obj|
  ...
end

attribute :tags, if: proc { |_, opt| opt[:with_tags?].present? } do |obj|
  ...
end

And now, send these with_? tags from the controller in params hash cherry-picking the attributes.

Personally, I feel this approach is better than the previous ones because we have not categorized the serializers and so, one attribute can co-exist with another independently. also, no need to create many serializer classes which are hard to maintain since there can be any combination of attributes that are needed.

Problem

The second approach is actually good but I think if we add native support for optional attributes in the serializer, the code will be much cleaner and others can also follow the same.

Proposed solution

CURRENT:

ArticlesSerializer.new(articles, { params: { with_tags?: true, with_popular?: true } })

attribute :tags, if: proc { |_, opt| opt[:with_tags?].present? } do |obj|
  ...
end

SOLUTION (BETTER WAY):

ArticlesSerializer.new(articles, optional: %i[tags popular])

attribute :tags, optional: true do |obj|
  ...
end

attribute :content, optional: true do |obj|
  ...
end

What do you guys think about this?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions