如何在哈希参数中重命名符号?

时间:2017-12-01 22:33:48

标签: ruby-on-rails json ruby postgresql api

我有一个来自外部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,而不是我在此描述的内容?

2 个答案:

答案 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不同的名称,但该名称足以说明这一想法。

顺便说一句,如果你将这个JSON发送到数据库中,那么你可能不需要打扰符号键,JSON只使用字符串作为键,所以你只需要将字符串转换为符号,然后将它们转换回来字符串。当然,如果你在将JSON拉出数据库时象征着密钥,那么你可能希望保持一致并全面使用符号。

答案 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}