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

Getting Rails 5 app to return JSON API format


I'm trying to get my app to return in lowercase camelcase for eventual JSON API formatting.

I've installed gem 'active_model_serializers' and created a new initializer with the following code in it:

ActiveModelSerializers.config.adapter = :json_api
ActiveModelSerializers.config.key_transform = :camel_lower

Then I have a small API that returns json, as all of the best internet applications do:

class Api::V1::UsersController < API::V1::BaseController
  def sky
      @user = User.find_by_id(params[:user_id])

      if @user
          obj =  {
              sky: {
                  sectors: @user.sectors,
                  slots: @user.slots
              }
          }

          render json: obj
      else
          raise "Unable to get Sky"
      end
  end

More on the API controller inheritance pattern: class API::V1::BaseController < ActionController::Base

The Problem

In my API response, things are still snake cased and I see this error in the console [active_model_serializers] Rendered ActiveModel::Serializer::Null but my research has led me to a dead end as to what to do.

Any suggestions would be very welcome. Thanks!


Solution

  • The problem is you're not calling an active record serializer in your controller, so those config settings aren't being picked up.

    Solution: Create a UserSerializer in "app/serializers/user_serializer.rb" that should look something like this:

    class UserSerializer < ActiveModel::Serializer
      attributes :id
    
      has_many :sectors
      has_many :slots
    end
    

    as well as similarly structured SectorSerializer and a SlotSerializer with all of the attributes you want from each (Here are the getting started docs and the general syntax docs for active record serializers)

    Then in your controller:

    class Api::V1::UsersController < API::V1::BaseController
      def sky
        @user = User.includes(:sectors, :slots).find_by_id(params[:user_id])
    
        if @user
          render json: @user
        else
          raise "Unable to get Sky"
        end
      end
    end
    

    Which will eager load :slots and :sectors with includes then calls your UserSerializer using your camel_case config options.