Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically convert hash keys to camelCase in JBuilder

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?

like image 390
Morozzzko Avatar asked Mar 12 '23 03:03

Morozzzko


1 Answers

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:

  1. 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
    
  2. 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.

like image 112
Morozzzko Avatar answered Mar 23 '23 16:03

Morozzzko