Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialization level setting #55

Open
railsfactory-selva opened this issue Sep 18, 2019 · 7 comments
Open

Serialization level setting #55

railsfactory-selva opened this issue Sep 18, 2019 · 7 comments

Comments

@railsfactory-selva
Copy link

Serialization level in AMS is set to ‘One level’ by default, which we can change it to deep nesting from config globally.

Do we have similar setting in Panko? If I'm not wrong, it seems Panko does deep nesting by default unless mentioned while invoking serializer like below

Panko::ArraySerializer.new(posts, only: {
instance: [:title, :body, :author, :comments],
author: [:id],
comments: {
instance: [:id, :author],
author: [:name]
}
})

It would be great, if we have config kind of stuff to set serialization level globally.

@yosiat
Copy link
Owner

yosiat commented Sep 18, 2019

@railsfactory-selva do you have any example why you would like to set filtering globally for all serializers? and can you point me to AMS example for setting it globally?

@railsfactory-selva
Copy link
Author

railsfactory-selva commented Sep 18, 2019

@yosiat We would like to have one-level serializer by default, and include nesting just whenever required as like AMS (or) there should be option to change it to 'one level' globally which would be helpful for many people.

In AMS, by default it's one-level and we can change it to deep nesting globally, by adding below code at initializers
ActiveModelSerializers.config.default_includes = '**'

Ref: https://stackoverflow.com/questions/32079897/serializing-deeply-nested-associations-with-active-model-serializers

@jeffblake
Copy link

This would also help me out a lot in trying to migrate off of AMS

@jeffblake
Copy link

@yosiat First of all, I've been playing with the library for a few hours and I'm really liking it so far. It takes all of the bloat and bad performance out of AMS, and keeps the good bits! In particular, I like that Panko does not hack itself into render json:.

In order for me to transition off AMS I need to be able to specify only and excludes of nested relationship attributes.

  1. I'd love to see a global config option to only serialize one level deep. This will prevent infinite loops, improve performance, and get me 90% of the way towards getting off AMS.
  2. As a workaround I've tried playing with the only and excludes options to try and mimic 1 level of serialization, but I'm getting hung up on specifying attributes and associations of nested relationships. For example, I've tried both:
    def self.filters_for(context, scope)
      {
        only: [:id, :name, { venue: [:id, :name]}]
      }
    end

and

    def self.filters_for(context, scope)
      {
        only: {
          instance: [:id, :name],
          venue: { instance: [:id, :name] }
        }
      }
    end

And a few other variations but I can never get the attributes/relationships of venue to filter.

I'll always get back:

        {
            "id": 80714,
            "name": "Stockholm 03.05.20",

        },
        {
            "id": 80955,
            "name": "StriveX"
        },

Where I want to see:

        {
            "id": 80714,
            "name": "Stockholm 03.05.20",
            "venue": {
              "id": 2,
              "name": "Theater"
            }
        }

I have to do this because venue has other associations (like address) that I don't want to render unless it's explicitly requested (goes back to the nested rendering issue).

The way AMS works now is I can pass in a string such as

venue,registration_types.prices and get back the venue association, plus a nested association of registration_types --> prices
All other associations are omitted because the user explicitly requested certain ones.

This is how AMS parses the string: https://github.com/jsonapi-rb/jsonapi-renderer/blob/master/lib/jsonapi/include_directive.rb

And details on how it works: https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/adapters.md#include-option

AMS splits the attributes and relationships into two separate options: fields and include. I like your DSL of combining it into one option, I just need to write a converter.

Thanks!

@jeffblake
Copy link

jeffblake commented Feb 23, 2020

I've also tried passing it into the ArraySerializer as such:

fields = { instance: [:id, :name, :start, :end],  registration_types: { instance: [:id, :name], prices: { instance: [:currency, :amount] }  }

Panko::ArraySerializer.new(collection, each_serializer: serializer, only: fields)

The subject in question is an Event (date, time, venue, etc)

I would expect this to only include the registration_types association, with the prices nested association, however I will also get back all other associations of the root object like venue, etc.

In other words, if I pass in a only option, I would expect that each attribute and association has to be whitelisted / present in that hash, in order to be rendered.

And if the only and exclude option is not present, it would default to rendering all of the attributes of the root object, and all of the attributes of the first level of associations.

Thoughts?

@esnrRahman
Copy link

esnrRahman commented Mar 9, 2020

Hello @yosiat ! Thanks so much for this gem. Definitely a better alternative to AMS and keeping it minimalistic allows developers to customize its serializer a lot.

Hello @jeffblake ! Thank you so much for posting this. I have been tearing my hair out with this issue. So definitely +1 this problem.

But the funny thing is I actually have two serializers. One works and the other doesn't. And the nature of both these serializers have been written in a similar format.

DOESNT WORK =>

Screen Shot 2020-03-08 at 10 35 46 PM

NOTE: Customer model is inherited from base User model. I am not sure whether that makes a difference.

NOTE 2: So sorry for the screenshot. I cant seem to code it out using the tildas.

The other one that works is of similar nature. Has a serializer that references another one. And in the class method, the association is filtered.

Apologies beforehand if the code snippet is not descriptive enough. Please let me know if anything is vague and will try to clarify! Thanks beforehand!

@esnrRahman
Copy link

esnrRahman commented Sep 24, 2020

Hey @jeffblake ! I was able to figure this out. This has been written somewhere (in fine print :P) in the docs. But if you try the following, it should work =>

 def self.filters_for(context, scope)
 {
      only: {
        instance: [:id, :name, :venue], # <= add venue here
        venue: { instance: [:id, :name] }
      }
}
end

As per docs written in the Associations sections -

Let's dissect only option we passed -

instance - list of attributes (and associations) we want to serializer for current instance of the serializer, in this case - PostSerializer.
author, comments - here we specify the list of attributes we want to serialize for each association.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants