在 JBuilder 中自动将哈希键转换为驼峰命名法

Mor*_*zko 5 ruby ruby-on-rails jbuilder

我使用的是 JBuilder 版本 2.4.1 和 Rails 4.2.6。我正在尝试将一个复杂的对象序列化为 JSON。代码如下:

json.key_format! camelize: :lower

json.data_object @foo
Run Code Online (Sandbox Code Playgroud)

@foo看起来像这样:

{
  key: 'value',
  long_key: 'value'
}
Run Code Online (Sandbox Code Playgroud)

我希望它呈现为

{
  "dataObject": {
    "key": "value",
    "longKey": "value"
  }
}
Run Code Online (Sandbox Code Playgroud)

但它保留了原始的哈希键,仅将 data_object 转换为驼峰命名法

{
  "dataObject": {
    "key": "value",
    "long_key": "value"
  }
}
Run Code Online (Sandbox Code Playgroud)

所以问题是:使用 JBuilder 驼峰化哈希键的正确方法是什么?

Mor*_*zko 6

正如 Bryce 所提到的,Jbuilder 使用 to_json 而不是处理哈希。

一个简单的解决方案是使用json.set!手动序列化哈希。

json.key_format! camelize: :lower

json.data_object do
  @foo.each do |key, value|
    json.set! key, value
  end
end
Run Code Online (Sandbox Code Playgroud)

不过,有一个问题:如果 @foo 为空,它根本不会创建对象。这些是我找到的解决方案:

  1. 在序列化之前定义一个空哈希

    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
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果源变量为空,则序列化一个空哈希

    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
    
    Run Code Online (Sandbox Code Playgroud)

    或者如果您更喜欢扁平化代码

    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?
    
    Run Code Online (Sandbox Code Playgroud)

但是,如果您必须序列化嵌套对象,这些解决方案将不起作用。您可以通过json在Jbuilder内对对象进行monkeypatching来实现深度序列化

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
Run Code Online (Sandbox Code Playgroud)

然后您就可以简单地使用json.hash! :data_object, @foo并获得所需的结果。