Search code examples
ruby-on-railsjsonrubyactive-model-serializersserialization

How to make RESTful root keys in versioned Active model serializer?


I have ruby on rails app with user_controller generated via scaffold.

 # app/controllers/api/v1/users_controller.rb
 class Api::V1::UsersController < Api::V1::ApiController
  skip_before_action :verify_authenticity_token
  serialization_scope :view_context

   def show
     render json: @user
   end
 end

The model

  # app/models/api/v1/user.rb
  class Api::V1::User < Api::V1::ApiRecord
    has_one_time_password

    validates_presence_of :phone
  end

And serializer:

 # app/serializers/api/v1/user_serializer.rb
  class Api::V1::UserSerializer < ActiveModel::Serializer
    attributes :id, :phone, :first_name, :email, :dob, :last_name, :gender, :otp_code

    def otp_code
        object.otp_code
    end
  end

Everything is fine but i got stuck in configuration. /api/v1/users/2 gives me below response.

   {
    "api/v1/user": {
        "id": 2,
        "phone": "999999999",
        "first_name": "Rajan",
        "email": "sample@h.com",
        "dob": "2000-01-01",
        "last_name": "Verma",
        "gender": "male",
        "otp_code": "503036"
      }
   }

Did you saw the root key? why it is coming with full namespace? it should be { "user": { ...data } } only.

I don't want to apply and patch or hacks for this trivial one. I think i am missing any configuration which i am not able to find in documentation.

Please help.


Solution

  • So it seems ActiveModel::Serializer uses the full model name including modules as the root key, see

    https://github.com/rails-api/active_model_serializers/blob/0-10-stable/lib/active_model/serializer.rb#L384-L391

    So either you set the root key in your controller.

    class UsersController < ApplicationController
      def index
        render json: @users, root: "users"
      end
    end
    

    Or if you never want to include the full name in your serializer you could create a base serializer

    # app/serializers/api/base_serializer.rb
    class BaseSerializer < ActiveModel::Serializer
      def json_key
        object.class.model_name.to_s.demodulize.underscore
      end
    end
    
    # app/serializers/api/v1/user_serializer.rb
    class Api::V1::UserSerializer < BaseSerializer
      attributes :id, :phone, :first_name, :email, :dob, :last_name, :gender, :otp_code
    
      def otp_code
        object.otp_code
      end
    end