Serializing deeply nested associations with active_model_serializers

Eric Norcross picture Eric Norcross · Aug 18, 2015 · Viewed 31.8k times · Source

I'm using Rails 4.2.1 and active_model_serializers 0.10.0.rc2

I'm new to API's and chose active_model_serializers because it seems to be becoming the standard for rails (Although I'm not opposed to using RABL or another serializer)

The problem I'm having is that I can't seem to include various attributes in multi-level relationships. For instance I have:

Projects

class ProjectSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name,
                                  :updated_at

  has_many                        :estimates, include_nested_associations: true

end

and Estimates

class EstimateSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :release_version, 
                                  :exchange_rate, 
                                  :updated_at,

                                  :project_id, 
                                  :project_code_id, 
                                  :tax_type_id 

  belongs_to                      :project
  belongs_to                      :project_code
  belongs_to                      :tax_type

  has_many                        :proposals

end

Proposals

class ProposalSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :updated_at,

                                  :estimate_id

  belongs_to                      :estimate
end

When I hit the /projects/1 the above produces:

{
  "id": 1,
  "name": "123 Park Ave.",
  "updated_at": "2015-08-09T02:36:23.950Z",
  "estimates": [
    {
      "id": 1,
      "name": "E1",
      "release_version": "v1.0",
      "exchange_rate": "0.0",
      "updated_at": "2015-08-12T04:23:38.183Z",
      "project_id": 1,
      "project_code_id": 8,
      "tax_type_id": 1
    }
  ]
}

However, what I'd like it to produce is:

{
  "id": 1,
  "name": "123 Park Ave.",
  "updated_at": "2015-08-09T02:36:23.950Z",
  "estimates": [
    {
      "id": 1,
      "name": "E1",
      "release_version": "v1.0",
      "exchange_rate": "0.0",
      "updated_at": "2015-08-12T04:23:38.183Z",
      "project": { 
        "id": 1,
        "name": "123 Park Ave."
      },
      "project_code": {
        "id": 8,
        "valuation": 30
      },
      "tax_type": {
        "id": 1,
        "name": "no-tax"
      },
      "proposals": [
        {
          "id": 1,
          "name": "P1",
          "updated_at": "2015-08-12T04:23:38.183Z"
        },
        {
          "id": 2,
          "name": "P2",
          "updated_at": "2015-10-12T04:23:38.183Z"
        }
      ]
    }
  ]
}

Ideally, I'd also like to be able to specify which attributes, associations, and attributes of those associations that are included in each serializer.

I've been looking through the AMS issues, and there does seem to be some back and forth on how this should be handled (or if this kind of functionality is even actually supported) but I'm having difficulty figuring out exactly what the current state is.

One of the proposed solutions was to override the attribute with a method to call the nested attributes, but that seems to be regarded as a hack so I wanted to avoid it if possible.

Anyway, an example of what of how to go about this or general API advice would be much appreciated.

Answer

Daniel D picture Daniel D · Jul 2, 2016

Per commit 1426: https://github.com/rails-api/active_model_serializers/pull/1426 - and related discussion, you can see that the default nesting for json and attributes serialization is one level.

If you want deep nesting by default, you can set a configuration property in an active_model_serializer initializer:

ActiveModelSerializers.config.default_includes = '**'

For detailed reference from v0.10.6: https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/adapters.md#include-option