Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON API style sideloading in Rails ActiveModel::Serializers

I'm trying to build a JSON API style API using AM::Serializer. I'm running into an issue with sideloading.

I want to be able to build JSON that looks like:

{
    "primaries": [{
        "id": 123,
        "data": "Hello world.",
        "links": {
            "secondaries": [ 1, 2, 3 ]
        }
    }],
    "linked" : {
        "secondaries": [
            {
                "id": 1,
                "data": "test1"
            },
            {
                "id": 2,
                "data": "test2"
            },
            {
                "id": 3,
                "data": "test3"
            }
        ]
    }
}

The code I've been able to come up with looks like:

class PrimarySerializer < ActiveModel::Serializer
  attributes :id, :data

  has_many :secondaries, key: :secondaries, root: :secondaries
  embed :ids, include: true
end

Which generates JSON that looks like:

{
    "primaries": [{
        "id": 123,
        "data": "Hello world.",
        "secondaries": [ 1, 2, 3 ]
    }],
    "secondaries": [
        {
            "id": 1,
            "data": "test1"
        },
        {
            "id": 2,
            "data": "test2"
        },
        {
            "id": 3,
            "data": "test3"
        }
    ]
}

Is there a way to override the location of the in-element secondaries and sideloaded secondaries such that they live in child nodes link and linked?

The above code is an abstraction of the actual code and may not work. Hopefully it illustrates the point sufficiently.

Thanks!

like image 710
will_in_wi Avatar asked May 02 '14 17:05

will_in_wi


1 Answers

ActiveModel Serializers can do this. The problem is that the built-in association methods are to restrictive. Instead you must build up the links & linked parts manually.

(This answer refers to the stable 0.8.1 version of ActiveModel Serializers)

Here's a Gist with a complete JSON-API solution https://gist.github.com/mars/97a637560109b8ddfb27

Example:

class ExampleSerializer < JsonApiSerializer # see Gist for superclass
  attributes :id, :name, :links

  def links
    {
      things: object.things.map(&:id),
      whatzits: object.whatzits.map(&:id)
    }
  end

  def as_json(*args)
    hash = super(*args)

    hash[:linked] = {
      things: ActiveModel::ArraySerializer.new(
          object.things,
          each_serializer: ThingsSerializer
        ).as_json,
      whatzits: ActiveModel::ArraySerializer.new(
          object.whatzits,
          each_serializer: WhatzitsSerializer
        ).as_json
    }

    hash
  end

end
like image 189
Mars Avatar answered Oct 08 '22 04:10

Mars