我有一个来自外部API的参数,它使用我希望适合我的Rails应用程序的CamelCase格式化JSON响应:
{"AccountID"=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE",
"ChannelProductDescription"=>"0004", "Currency"=>"CAD",
"CurrentBalance"=> {"Amount"=>"162563.64", "Currency"=>"CAD"}}
使用以下脚本我将它们转换为小写:
data = JSON.parse(response, symbolize_keys: true)
data = {:_json => data} unless data.is_a?(Hash)
data.deep_transform_keys!(&:underscore)
data.deep_symbolize_keys!
让我正确格式化params
,如下所示:
{:account_id=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE",
:channel_product_description=>"SAVINGS", :currency=>"CAD",
:current_balance=> {:amount=>"43.00", :currency=>"CAD"}}
我尝试将此外部API响应映射到通用Rails模型Account
,其中来自此API调用的JSON将作为参数干净地返回到我的数据库中,以允许干净的保存接口,例如: / p>
@account = Account.create(ParamParser.call(params))
但是我遇到了转换:account_id
的问题,因为该参数与我的数据库的主键冲突。
为了解决这个问题,我的想法是将params[:account_id]
的所有符号实例转换为params[:account_key_id]
,以便这些参数不会与我的数据库现有account_id
字段发生冲突。
我该如何做到这一点,是否有更好的方法来使用外部JSON API,而不是我在此描述的内容?
答案 0 :(得分:1)
Hash#deep_transform_keys
这样做:
返回一个新的哈希,其中包含由块操作转换的所有键。 这包括来自根哈希和所有密钥的密钥 嵌套的哈希和数组。
所以你可以使用适当的块一次性完成它,例如:
data.deep_transform_keys! do |key|
key = key.underscore.to_sym
key = :account_key_id if(key == :account_id)
key
end
您也可以将symbolize_keys: true
标记放到JSON.parse
,无论如何都要更改所有密钥,所以不要打扰。
如果你做了很多这样的事情,那么你可以编写一个方法来获取键映射哈希并给你一个lambda来转换键:
def key_mangler(key_map = { })
->(key) do
key = key.underscore.to_sym
key = key_map[key] if(key_map.has_key?(key))
key
end
end
然后说出类似的话:
data.deep_transform_keys!(&key_mangler(:account_id => :account_key_id))
当然,您可能希望使用与key_mangler
不同的名称,但该名称足以说明这一想法。
答案 1 :(得分:1)
除了上一个答案......
不幸的是,据我所知,在一次操作中没有关于Hash的方法。我总是通过强力实现这一点,如:
hash[:new_key] = hash[:old_key]
hash.delete(:old_key)
以下评论中提出的“mu太短”的快捷方式是:
hash[:new_key] = hash.delete(:old_key)
用irb来说明:
2.4.1 :002 > h = { foo: :bar }
=> {:foo=>:bar}
2.4.1 :003 > h[:foo_new] = h.delete(:foo)
=> :bar
2.4.1 :004 > h
=> {:foo_new=>:bar}