I have a very simple model that I wish to serialize in a Rails (5) API. I want to produce the resulting JSON keys as CamelCase (because that's what my client expects). Because I expect the model to increase in complexity in future, I figured I should use ActiveModelSerializers. Because the consumer of the API expects a trivial JSON object, I want to use the :attributes
adapter. But, I cannot seem to get AMS to respect my setting of :key_transform, regardless of whether I set ActiveModelSerializers.config.key_transform = :camel
in my configuration file or create the resource via s = ActiveModelSerializers::SerializableResource.new(t, {key_transform: :camel})
(where t
represents the ActiveModel object to be serialized) in the controller. In either case, I call render json: s.as_json.
Is this a configuration problem? Am I incorrectly expecting the default :attributes
adapter to respect the setting of :key_transform
(this seems unlikely, based on my reading of the code in the class, but I'm often wrong)? Cruft in my code? Something else?
If additional information would be helpful, please ask, and I'll edit my question.
Controller(s):
class ApplicationController < ActionController::API
before_action :force_json
private
def force_json
request.format = :json
end
end
require 'active_support'
require 'active_support/core_ext/hash/keys'
class AvailableTrucksController < ApplicationController
def show
t = AvailableTruck.find_by(truck_reference_id: params[:id])
s = ActiveModelSerializers::SerializableResource.new(t, {key_transform: :camel})
render json: s.as_json
end
end
config/application.rb
require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)
module AvailableTrucks
class Application < Rails::Application
config.api_only = true
ActiveModelSerializers.config.key_transform = :camel
# ActiveModelSerializers.config.adapter = :json_api
# ActiveModelSerializers.config.jsonapi_include_toplevel_object = false
end
end
class AvailableTruckSerializer < ActiveModel::Serializer
attributes :truck_reference_id, :dot_number, :trailer_type, :trailer_length, :destination_states,
:empty_date_time, :notes, :destination_anywhere, :destination_zones
end
FWIW, I ended up taking an end-around to an answer. From previous attempts to resolve this problem, I knew that I could get the correct answer if I had a single instance of my model to return. What the work with ActiveModel::Serialization was intended to resolve was how to achieve that result with both the #index
and #get
methods of the controller.
Since I had this previous result, I instead extended it to solve my problem. Previously, I knew that the correct response would be generated if I did:
def show
t = AvailableTruck.find_by(truck_reference_id: params[:id])
render json: t.as_json.deep_transform_keys(&:camelize) unless t.nil?
end
What had frustrated me was that the naive extension of that to the array returned by AvailableTruck.all
was failing in that the keys were left with snake_case.
It turned out that the "correct" (if unsatisfying) answer was:
def index
trucks = []
AvailableTruck.all.inject(trucks) do |a,t|
a << t.as_json.deep_transform_keys(&:camelize)
end
render json: trucks
end