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

Documented alternative to 0.8 embed :ids, include: true in 0.10.x #2006

Closed
goelinsights opened this issue Dec 18, 2016 · 16 comments
Closed

Documented alternative to 0.8 embed :ids, include: true in 0.10.x #2006

goelinsights opened this issue Dec 18, 2016 · 16 comments

Comments

@goelinsights
Copy link

goelinsights commented Dec 18, 2016

Expected behavior vs actual behavior

I know this is a breaking change. However, I'm unable to replicate what I could do previously and despite a number of pull requests cited in previous issues, the fix appears to be to use the JSON-API adapter, e.g., @NullVoxPopuli #1111

(note: I have a number of duplicate objects nested and I want to sideload the data in a redux store that then filters the object by id in the front-end (angular 2). Since this is a front-end site, I'm trying to limit API calls as much as possible and cache as much as I can in each request on the front-end, especially for mobile offline use. I find the JSON API format counter-productive to this use case (included relative to original is irrelevant and the format is overly verbose for what is already a large data pull), so I'm trying to do in AMS 0.10.x what I could do easily in 0.8.x with the commands embed :ids, include: true). I've tried embed: :ids at the serializer level and it seems to nest the data in my serialized JSON rather than insert the id and sideload the associated data.

Is this still possible in AMS 0.10.x or should I stick to 0.8 or try the initializer in 0.9 that was deprecated?

Example desired output with objects referenced by id and then sideloaded into the root by object name:

{
  "authors": 
  [
    {"id": 1, "name": "Ghost Writer", "book_ids":[1,2,5, 7, 8, 9, 10, 15]}, 
    {"id":2, "name": "Celebrity Nonwriter", "book_ids":[1,5,15], "publisher_id": 3}
  ],
  "books": 
   [
     {"id": 1, "title": "Art of the Deal", "author_ids": [1,2], "publisher_id": 3}
    ],
   "publishers": [
     {"id": 3, "name": "Ghostwriter Press"}
    ]
}

Steps to reproduce

(e.g., detailed walkthrough, runnable script, example application)
tried to upgrade to 0.10.3 (via bundle update)

Environment

ActiveModelSerializers Version (commit ref if not on tag): 0.10.3

Output of ruby -e "puts RUBY_DESCRIPTION":

OS Type & Version:

Integrated application and version (e.g., Rails, Grape, etc): rails 4.2.6

Backtrace

(e.g., provide any applicable backtraces from your application)

Additonal helpful information

(e.g., Gemfile.lock, configurations, PR containing a failing test, git bisect results)

@goelinsights goelinsights changed the title Documented alternative to 0.8 embed :ids, include: true in 0.10 Documented alternative to 0.8 embed :ids, include: true in 0.10.x Dec 18, 2016
@bf4
Copy link
Member

bf4 commented Dec 18, 2016

That data structure requires a custom adapter, or perhaps an extension of the JSON adapter

@goelinsights
Copy link
Author

goelinsights commented Dec 24, 2016

@bf4 I'm wondering why that functionality was removed, which existed up until 0.9.5. Seems odd outside of the increasing tie between AMS and Ember data. If sideloading associated data is going to be problematic (and in the prior versions, this broke on caching), looks like Jbuilder is the right path forward for me, given deprecated support for the 0.8.x and 0.9.x branches and compatibility issues with Rails 5.

As I go deeper I'll need fragment caching, russian doll caching, sideloaded object caching with multi-fetch...all seem to be a bit outside the scope of the current capabilities of the project and I certainly don't want to swim upstream against the needs/ optimizations for the current community.

@bf4
Copy link
Member

bf4 commented Dec 24, 2016 via email

@rahilsondhi
Copy link

Does anyone have an adapter that allows "sideloading" so you can have multiple roots? I'm also forced to switch to jbuilder for the same reason.

@bf4
Copy link
Member

bf4 commented Feb 1, 2017

@rahilsondhi you're going to need to be more specific. JSON API allows sideloading. Do you mean a similar format to embed ids?

{
  "authors": 
  [
    {"id": 1, "name": "Ghost Writer", "book_ids":[1,2,5, 7, 8, 9, 10, 15]}, 
    {"id":2, "name": "Celebrity Nonwriter", "book_ids":[1,5,15], "publisher_id": 3}
  ],
  "books": 
   [
     {"id": 1, "title": "Art of the Deal", "author_ids": [1,2], "publisher_id": 3}
    ],
   "publishers": [
     {"id": 3, "name": "Ghostwriter Press"}
    ]
}

@rahilsondhi
Copy link

rahilsondhi commented Feb 1, 2017

Sorry I guess I was confused about what "sideloading" means. But yes, I'm trying to achieve the JSON response you pasted - multiple keys at the root for different object types, like you have authors and books in your example.

I used to be able to achieve this in version 0.8.2, but it doesn't seem possible in 0.10.0.

class AlbumSerializerWithAssocs < AlbumSerializer
  root :album
  has_one :artist, serializer: ArtistSerializer, root: :artist, embed: :id, include: true
  has_many :tracks, serializer: TrackSerializer, root: :tracks, embed: :id, include: true
end
{
  "album": {attrs},
  "artist": {attrs},
  "tracks": [track, track, track]
}

@bf4
Copy link
Member

bf4 commented Feb 1, 2017

@rahilsondhi It's definitely possible. You can write any adapter you want. It doesn't come out of the box at this point. I'd support a PR to add an adapter or mixin that supports 'legacy ams'.

@bf4
Copy link
Member

bf4 commented Feb 1, 2017

However, I think you could just add an attribute to the AuthorSerializer (any particular reason you changed the example to Albums?)

attributes :book_ids, :author_ids
has_many :authors
has_many :books

@pistachiomatt
Copy link

@rahilsondhi @goelinsights If you end up writing an adapter, ping me! It's the only thing holding me back from an upgrade.

@goelinsights
Copy link
Author

goelinsights commented Mar 2, 2017 via email

@vaibhav8275
Copy link

You can get book ids in json by using example below:

attribute book_ids

def book_ids
  object.books.pluck_id
end

@drewnichols
Copy link

Anyone aware of a solution to this which will support embedded ids the way AMS 9 worked?

@bf4
Copy link
Member

bf4 commented May 11, 2017

@drewnichols could you help me with what's different in 0.9 vs. #2006 (comment) ?

@drewnichols
Copy link

Sure, assuming we models Foo and Bar as follows:

class Foo < ActiveRecord::Base
  has_many :bar 
end

class Bar < ActiveRecord::Base
  belongs_to :foo
end

Using 9.x we could embed the Bar ids and include a key for the Bar objects as follows:

{
  "foo" : {
    "bar_ids" : [ 1, 2, 3 ]
  },
  "bars" : [
    { "id" : 1 },
    { "id" : 2 },
    { "id" : 3 }
  ]
}

It seams (and I'd love to discover i'm wrong) that the JSON adapter for 10 only supports the following style:

{
  "foo" : {
    "bars" : [
      { "id" : 1 },
      { "id" : 2 },
      { "id" : 3 }
    ]
  }
}

In this trivial example either will work ok however if you're hitting an index route of Foos and you want to include the Bars in the document you will have a number of repeated instances of Bar which can make the document rather large. For example:

{
  "foos" : [
    { 
      "id" : 1,
      "bars" : [
        { "id" : 1 },
        { "id" : 2 },
        { "id" : 3 }
      ]
    }, {
      "id" : 2,
      "bars" : [
        { "id" : 1 },
        { "id" : 2 },
        { "id" : 3 }
      ]
    }
  ]
}

This embedding ids style is super useful when working with, at least in my case, Ember projects as we can load a number of records together into Ember Data within 1 request. From what I can tell in AMS 10 I can get the array of embedded IDs by adding an attribute to the serializer with the suffix _ids like this:

class FooSerializer < ActiveModel::Serializer
  attributes :bar_ids
end

or I can get the array of child models like this:

class FooSerializer < ActiveModel::Serializer
  has_many :bars
end

but I can't get the embedded ids with the additional root key of "bars" containing an array of serialized Bars.

@PratheepV
Copy link

@bf4 is there any workaround for this as of now?.

Anyone has custom adapter for this.

@drewnichols
Copy link

@PratheepV It looks like one of us is going to have to setup up and make it happen.

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

No branches or pull requests

7 participants