Tom Pinchen
Tom Pinchen

Reputation: 2497

Serializing Nested Attributes Active Model Serializer

I have the following code and can't seem to get my JSON to output as per my serializer.

I receive the following log [active_model_serializers] Rendered SimpleJobSerializer with Hash

My controller is as below:

# Jobs Controller

def home
    return_limit = 2

    @dev_jobs = Job.where(category: 'developer').limit(return_limit)
    @marketing_jobs = Job.where(category: 'marketing').limit(return_limit)
    @sales_jobs = Job.where(category: 'sales').limit(return_limit)


    @jobs = {
      developer: @dev_jobs,
      marketing: @marketing_jobs,
      sales: @sales_jobs
    }

    render json: @jobs, each_serializer: SimpleJobSerializer
  end

And my serializer:

class SimpleJobSerializer < ActiveModel::Serializer
  attributes :title, :company, :job_type, :date

  def date
    d = object.created_at
    d.strftime("%d %b")
  end
end

I am receiving the full API response but expect to only receive title, company, job_type and date.

It's worth mentioning the jobs model is completely flat and there are currently no associations to take into account. It seems to be just the nesting of the jobs into the @jobs object that's stopping serialization.

Any help would be much appreciated.

Upvotes: 2

Views: 2491

Answers (1)

Anthony
Anthony

Reputation: 15957

each_serializer expects you to pass an array but here you're passing a hash:

@jobs = {
  developer: @dev_jobs,
  marketing: @marketing_jobs,
  sales: @sales_jobs
}

Since you want that structure, I'd recommend two approachs depending on which you prefer. One is to change the serializer which should control the format:

class JobsSerializer < ActiveModel::Serializer
  attributes :developer, :marketing, :sales

  def developer
    json_array(object.where(category: "developer"))
  end

  def marketing
    json_array(object.where(category: "marketing"))
  end

  def sales
    json_array(object.where(category: "sales"))
  end

  def json_array(jobs)
    ActiveModel::ArraySerializer.new(jobs, each_serializer: SimpleJobSerializer)
  end
end

You can still leave your current serializer as is:

class SimpleJobSerializer < ActiveModel::Serializer
  attributes :title, :company, :job_type, :date

  def date
    d = object.created_at
    d.strftime("%d %b")
  end
end

Or option 2 would be to do this in the controller:

@jobs = {
  developer: ActiveModel::ArraySerializer.new(@dev_Jobs, each_serializer: SimpleJobSerializer),
  marketing: ActiveModel::ArraySerializer.new(@marketing_jobs, each_serializer: SimpleJobSerializer),
  sales: ActiveModel::ArraySerializer.new(@sales_jobs, each_serializer: SimpleJobSerializer)
}

render json: @jobs

Upvotes: 3

Related Questions