Search code examples
ruby-on-railsactive-model-serializersjson-api

Serialize relationships with custom fields in ActiveModelSerializer


I'm having a bit of trouble using ActiveModelSerializers to serialize my model correctly. The setup is as follows:

# controllers/posts_controller.rb
class PostsController < ApplicationController

  def index
   render json: @posts, each_serializer: PostSerializer, include: %w(comments), fields: post_fields
  end

  private

  def post_fields
    { posts: [:name, :content, :author] }
  end
end

# serializers/post_serializer.rb
class PostSerializer < ActiveModelSerializer
  attributes :name, :content, :author
  has_many :comments, serializer: CommentSerializer
end

When I make a request to the posts#index endpoint, I'm expecting a JSON response that is formatted to the JSON-API spec, like the following:

{
  "data": {
    "type": "post",
    "id": 1,
    "attributes": {
      "name": "My first post",
      "author": "Mr. Glass",
      "content": "This is my first post ..."
    },
    "relationships": {
      "comments": {
        "data": {
          "id": 1,
          "type": "comments"
        }
      }
    }
  },
  "included": {
    "type": "comments",
    "id": 1,
    "attributes": {
      "content": "First!"
    }
  }
}

However, the actual response is this:

{
  "data": {
    "type": "post",
    "id": 1,
    "attributes": {
      "name": "My first post",
      "author": "Mr. Glass",
      "content": "This is my first post ..."
    }
  },
  "included": {
    "type": "comments",
    "id": 1,
    "attributes": {
      "content": "First!"
    }
  }
}

And the whole relationship block is just missing. Is there a way to get the relationship block in the actual response to show up again?


Solution

  • I figured it out!

    For any future readers - if you want to have the relationships block present in ActiveModelSerializers as well as using the fields option, you will need to do the following:

    # in your controller
    render json: @posts, include: %(comments), fields: post_fields
    
    def post_fields
      # note the inclusion of "comments" in the array of fields to be 
      # serialized. That is the change you will need to make.
      { posts: [:name, :author, :content, :comments] }
    end
    

    Hope that helps!