I am using JBuilder version 2.4.1 and Rails 4.2.6. I am trying to serialize a complex object to JSON. The code looks as follows:
json.key_format! camelize: :lower
json.data_object @foo
@foo looks like this:
{
  key: 'value',
  long_key: 'value'
}
I expect it to be rendered as
{
  "dataObject": {
    "key": "value",
    "longKey": "value"
  }
}
But instead it keeps the original hash keys, only converting data_object into camelCase
{
  "dataObject": {
    "key": "value",
    "long_key": "value"
  }
}
So the question is: what is the proper way to camelize hash keys using JBuilder?
As Bryce has mentioned, Jbuilder uses to_json instead of processing the hash.
A simple solution is to use json.set! to manually serialize the hash. 
json.key_format! camelize: :lower
json.data_object do
  @foo.each do |key, value|
    json.set! key, value
  end
end
Although, there is an issue: if @foo is empty, it won't create an object at all. These are the solutions I found:
Define an empty hash before the serialization
json.key_format! camelize: :lower
json.data_object({}) # don't forget parentheses or Ruby will handle {} as a block 
json.data_object do
  @foo.each do |key, value|
    json.set! key, value
  end
end
Serialize an empty hash if the source variable is empty
json.key_format! camelize: :lower
if (@foo.empty?) do 
  json.data_object({})
else 
  json.data_object do
    @foo.each do |key, value|
      json.set! key, value
    end
  end
end
Or if you prefer your code flat
json.key_format! camelize: :lower
json.data_object({}) if @foo.empty?
json.data_object do
  @foo.each do |key, value|
    json.set! key, value
  end
end unless @foo.empty?
However, those solutions will not work if you have to serialize nested objects. You can achieve deep serialization by monkeypatching the json object inside Jbuilder
def json.hash!(name, hash)
  if hash.empty?
    set! name, {}
  else
    set! name do
      hash.each do |key, value|
        if value.is_a?(Hash)
          hash! key, value
        else
          set! key, value
        end
      end
    end
  end
end
Then you can simply use json.hash! :data_object, @foo and get the desired result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With