Paras
Paras

Reputation: 3491

Rails ActiveModel Serializer : Retrieving Deeply Nested ActiveRecord Association

I'm using ActiveModel::Serializer to serialize my json data. I have three models as follows

class Invoice < ApplicationRecord
  has_many :invoiceDetails, inverse_of: :invoice
  belongs_to :customer
  accepts_nested_attributes_for :invoiceDetails
end

class InvoiceDetail < ApplicationRecord
  belongs_to :invoice
  belongs_to :product
end

class Product < ApplicationRecord
  belongs_to :company
  belongs_to :category
  belongs_to :user
  has_many :invoice_details
end

The serializers are as follows :

class InvoiceSerializer < ActiveModel::Serializer
  attributes :id, :total_amount, :balance_amount, :created_at
  belongs_to :customer
  has_many :invoiceDetails
end


class InvoiceDetailSerializer < ActiveModel::Serializer
  attributes :id, :quantity
  belongs_to :product
  belongs_to :invoice
end

class ProductSerializer < ActiveModel::Serializer
  attributes :id, :name, :mrp, :sp, :cp, :stocks, :isPublished
  has_one :category
end

When I retrieve an invoice I get the attributes from the associated invoiceDetails model and customer model but the attributes from the product model associated with the invoiceDetails model are missing.

For example if I retrieve an invoice, this is the output :

[
    {
        "id": 3,
        "total_amount": 450,
        "balance_amount": 350,
        "created_at": "2017-06-27T17:02:20.000Z",
        "customer": {
            "id": 4,
            "company_id": 1,
            "name": "vivek",
            "isActive": true,
            "created_at": "2017-06-27T14:35:50.000Z",
            "updated_at": "2017-06-27T14:35:50.000Z",
            "mobile": "12345678",
            "address": "test",
            "pan_number": null,
            "tin_number": null,
            "party_name": "vipul jwelers"
        },
        "invoiceDetails": [
            {
                "id": 4,
                "quantity": 1
            },
            {
                "id": 5,
                "quantity": 1
            }
        ]
    }
]

However if I retrieve invoiceDetail directly I get the associated model attributes.

**[
    {
        "id": 6,
        "quantity": 5,
        "product": {
            "id": 4,
            "name": "Test Prod",
            "mrp": 150,
            "sp": 130,
            "cp": 100,
            "stocks": 100,
            "isPublished": true
        },
        "invoice": {
            "id": 4,
            "total_amount": 3903,
            "balance_amount": 3,
            "created_at": "2017-07-01T07:45:02.000Z"
        }
    },
    {
        "id": 7,
        "quantity": 10,
        "product": {
            "id": 5,
            "name": "Test Prod 2",
            "mrp": 300,
            "sp": 250,
            "cp": 200,
            "stocks": 10,
            "isPublished": true
        },
        "invoice": {
            "id": 4,
            "total_amount": 3903,
            "balance_amount": 3,
            "created_at": "2017-07-01T07:45:02.000Z"
        }
    }
]**

So for retrieving the nested attributes directly from invoice, do I need to change the relationship among my models?

Has someone encountered the same problems, or any work around you can suggest?

Upvotes: 3

Views: 1788

Answers (1)

Paras
Paras

Reputation: 3491

If someone is stuck over this problem, here is what I did :

Whenever I want to retrieve the deeply nested association I add the "include **" keyword in the controller during response.

For example :

def show
    cust_id = params[:customer_id]
    invoice_id = params[:id]
    if cust_id && invoice_id
      invoice = Invoice.where(:id => invoice_id, :customer_id => cust_id)
      render json: invoice, include: '**', status: 200
    else
      render json: { errors: "Customer ID or Invoice ID is NULL" }, status: 422
    end
  end

The include * * will retrieve all the nested attributes for the invoice model using the serializer if defined for the respective models.

Upvotes: 4

Related Questions