Active_model_serializers: Setting root key strategy globally for json adapter

Created on 24 Feb 2016  路  6Comments  路  Source: rails-api/active_model_serializers

After updating to v0.10.0.rc4 tag I had to specify ActiveModelSerializers.config.adapter = :json in an initializer for a rails application in order to make active_model_serializer to add root key to the the response. However if the model is nested the key is built using the whole class name. For example if I specify a model:

class Users::Profile < ActiveRecord::Base
end

and then in controller:

class Users::ProfilesController < ApplicationController
  def show
    @profile = Users::Profile.first
     respond_with @profile, serializer: UserProfileSerializer
  end
end

It will build json containing the root key as follows: {'users/profile': {'name': 'test'}}. Is there any way to make active_model_serializer to use the class itself ignoring nesting? I've looked through the source code and found a method json_key which builds the root element of the json. But overriding that method is not always working. Moving root element build method to a overridable strategy may be a good feature request candidate

Feature Ready for PR 0.10.x

Most helpful comment

I see two other solutions here:

  • Create your own ProfileCollectionSerializer like so:
class ProfileCollectionSerializer < ActiveModel::Serializer::CollectionSerializer
  def json_key
    "profiles"
  end
end
render json: @profiles, serializer: ProfileCollectionSerializer
  • define a wrapper around the cancan collection that responds to #name:
class CollectionWrapper
  include Enumerable
  delegate :each, to: :@collection
  attr_reader :name

  def initialize(collection, name)
    @collection = collection
    @name = name
  end
end
render json: CollectionWrapper.new(@profiles, :profiles)

All 6 comments

I've found a way to reproduce the issue when json_key method is not called. If you respond_with empty collection of a given type (fetched by cancancan method load_and_authorize_resource) in index action it will ignore the json_key and render an empty collection with wrong root key.

What about using the :root options like so:

render json: @profile, serializer: UserProfileSerializer, root: "profile"

?

I see two other solutions here:

  • Create your own ProfileCollectionSerializer like so:
class ProfileCollectionSerializer < ActiveModel::Serializer::CollectionSerializer
  def json_key
    "profiles"
  end
end
render json: @profiles, serializer: ProfileCollectionSerializer
  • define a wrapper around the cancan collection that responds to #name:
class CollectionWrapper
  include Enumerable
  delegate :each, to: :@collection
  attr_reader :name

  def initialize(collection, name)
    @collection = collection
    @name = name
  end
end
render json: CollectionWrapper.new(@profiles, :profiles)

@groyoh Those are all valid options, the only concern is that they force you to be explicit about how you define the root element name. I've created a pull requests which should allow you to implicitly use json_key from item serializer when resource is an empty relation

@RomanKapitonov

Is there any way to make active_model_serializer to use the class itself ignoring nesting?

There is a type attribute you can use in the serializer if you're using JSON API. (Eventually this should replace the json_key method).

I've found a way to reproduce the issue when json_key method is not called. If you respond_with empty collection of a given type[...] it will ignore the json_key and render an empty collection with wrong root key.

Which is addressed in your PR https://github.com/rails-api/active_model_serializers/pull/1537 Thanks!

Did #1618 resolve this?

Was this page helpful?
0 / 5 - 0 ratings