Rails Serialization - fast_jsonapi / active_model_serializers

2.2k Views Asked by At

I am a bit lost getting on board fast_jsonapi / active_model_serializers to build an API. I have the basics down but seem stuck on a custom solution.

I have this as a serializer:

class AreaSerializer
  include FastJsonapi::ObjectSerializer
  attributes :id, :name, :cost_center, :notes
  has_many :children
end

In my area model I have:

  has_many :children, -> { Area.where(ancestry: id) }

My controller looks like:

class Api::V1::AreasController < ApiController

  def index
    render json: AreaSerializer.new(Area.root).serialized_json
  end

end

Areas are nested in a hierarchy with the ancestry gem. The output is:

{
"data": [{
    "id": "1",
    "type": "area",
    "attributes": {
        "id": 1,
        "name": "Calgary",
        "cost_center": "123456",
        "notes": ""
    },
    "relationships": {
        "children": {
            "data": [{
                "id": "3",
                "type": "child"
            }]
        }
    }
}, {
    "id": "2",
    "type": "area",
    "attributes": {
        "id": 2,
        "name": "Edmonton",
        "cost_center": "78946",
        "notes": ""
    },
    "relationships": {
        "children": {
            "data": []
        }
    }
}]

}

I am looking for an out put like this:

{
"data": [{
    "id": "1",
    "type": "area",
    "attributes": {
        "id": 1,
        "name": "Calgary",
        "cost_center": "123456",
        "notes": ""
    },
    "relationships": {
        "areas": {
            "data": [{
                "id": "3",
                "type": "area",
                "attributes": {
                    "id": 3,
                    "name": "Child Area",
                    "cost_center": "123456",
                    "notes": ""
                }
            }]
        }
    }
}, {
    "id": "2",
    "type": "area",
    "attributes": {
        "id": 2,
        "name": "Edmonton",
        "cost_center": "78946",
        "notes": ""
    }
}]

}

The idea being where the nested relationship shows the details etc.

3

There are 3 best solutions below

0
On

I started using the technique listed above but ended up forking and re-writing the jsonapi-serializer gem so it allows nesting (up to 4 levels deep) and does away with the concept of having relationships and attributes keys. I was also frustrated that it only output ID and TYPE keys of which TYPE is redundant most of the time since the object typically stays the same class in an array as an example and people seldom use real polymorphism (although it still supports this and outputs ID/type for polymorphic relationships).

Probably the best part of my re-write is that it allows deterministic field select-ability anywhere within the json key tree via a new fields input.

https://github.com/rubesMN/jsonapi-serializer

0
On

I just started using fast_jsonapi in my rails project.

fast_jsonapi adheres to JSON:API spec which you can see here.

So, you will not be able to use the relationship helper functions (:has_many, :belongs_to) to achieve the output you want, which is nesting the attributes of area inside the relationships key.

"relationships": {
        "areas": {
            "data": [{
                "id": "3",
                "type": "area",
                "attributes": { // nesting attributes of area
                    "id": 3,
                    "name": "Child Area",
                    "cost_center": "123456",
                    "notes": ""
                }
            }]
        }
    }

JSON:API specifies that:

To reduce the number of HTTP requests, servers MAY allow responses that include related resources along with the requested primary resources. Such responses are called “compound documents”.

So instead, you will have the attributes of area inside a key called included.

In order to get the included key in your response, you will need to provide an options hash in your controller to the serializer.

I don't quite understand your model Area relationships, but assume an Area has many SubArea.

class Api::V1::AreasController < ApiController

  def index
    // serializer options
    options = {
      include: [:sub_area],
      collection: true
    }
    render json: AreaSerializer.new(Area.root, options).serialized_json
  end

end
0
On

You Cannot use Association in fast_jsonapi . To Get a response in nested format . You need to add methods and need to create another serializer .

class AreaSerializer
  include FastJsonapi::ObjectSerializer

  set_type 'Area'

  attributes :id, :name, :cost_center, :notes

 attribute :childrens do |area, params|
     ChildrenSerializer.new(area.childrens, {params: 
     params})
  end
end

class ChildrenSerilizer
   include FastJsonapi::ObjectSerializer
    set_type 'Area'
    attributes :id, :name ... 
end