简体   繁体   English

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

[英]How to rename a symbol in hash parameters?

I have parameters from an external API that formats JSON responses using CamelCase that I want to fit into my Rails app: 我有来自外部API的参数,这些参数使用我想适合我的Rails应用的CamelCase格式化JSON响应:

{"AccountID"=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE", 
"ChannelProductDescription"=>"0004", "Currency"=>"CAD", 
"CurrentBalance"=> {"Amount"=>"162563.64", "Currency"=>"CAD"}}

Using the below script I converted them to lower case: 使用以下脚本,我将它们转换为小写:

data = JSON.parse(response, symbolize_keys: true)
data = {:_json => data} unless data.is_a?(Hash)
data.deep_transform_keys!(&:underscore)
data.deep_symbolize_keys!

Leaving me correctly formatted params like this: 让我这样正确格式化params

{:account_id=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE", 
:channel_product_description=>"SAVINGS", :currency=>"CAD", 
:current_balance=> {:amount=>"43.00", :currency=>"CAD"}}

I'm trying to map this external API response into a generic Rails model Account , where JSON from this API call will return cleanly as parameters into my database to allow a clean saving interface such as: 我正在尝试将此外部API响应映射到通用的Rails模型Account ,该API调用中的JSON将作为参数干净地返回到我的数据库中,以允许一个干净的保存接口,例如:

@account = Account.create(ParamParser.call(params))

But I ran into a problem with converting :account_id , as that param conflicts with the primary key of my database. 但是我遇到了转换:account_id的问题,因为该参数与数据库的主键冲突。

To get around this, my idea is to convert all symbol instances of params[:account_id] into params[:account_key_id] , so that those params don't conflict with my databases existing account_id field. 为了解决这个问题,我的想法是将params[:account_id]所有符号实例转换为params[:account_key_id] ,以使这些参数不会与我的数据库现有的account_id字段冲突。

How do I do this, and is there a better approach for consuming external JSON API's than what I've described here? 我该怎么做?有没有比这里描述的更好的方法来使用外部JSON API?

Hash#deep_transform_keys does this: Hash#deep_transform_keys这样做:

Returns a new hash with all keys converted by the block operation. 返回具有由块操作转换的所有键的新哈希。 This includes the keys from the root hash and from all nested hashes and arrays. 这包括来自根哈希以及所有嵌套哈希和数组的键。

So you could do it in one pass with an appropriate block, something like: 因此,您可以使用适当的代码块一口气完成此操作,例如:

data.deep_transform_keys! do |key|
  key = key.underscore.to_sym
  key = :account_key_id if(key == :account_id)
  key
end

You might as well drop the symbolize_keys: true flag to JSON.parse too, you're changing all the keys anyway so don't bother. 您也可以将symbolize_keys: true标志也放到JSON.parse ,无论如何您都在更改所有键,所以不要打扰。

If you're doing this sort of thing a lot then you could write a method that takes a key mapping Hash and gives you a lambda for transforming the keys: 如果您经常做这种事情,那么您可以编写一个方法,该方法采用键映射哈希,并为您提供用于转换键的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

and then say things like: 然后说像这样的话:

data.deep_transform_keys!(&key_mangler(:account_id => :account_key_id))

You might want to use a different name than key_mangler of course but that name is good enough to illustrate the idea. 您可能想要使用与key_mangler不同的名称,但是该名称足以说明这个想法。


BTW, if you're sending this JSON into the database then you probably don't need to bother with symbol keys, JSON only uses strings for keys so you'll be converting strings to symbols only for them to be converted back to strings. 顺便说一句,如果您要将此JSON发送到数据库中,那么您可能不必费心使用符号键,JSON仅将字符串用于键,因此您将仅将字符串转换为符号,以便将它们转换回字符串。 Of course, if you're symbolizing the keys when pulling the JSON out of the database then you'll probably want to be consistent and use symbols across the board. 当然,如果在从数据库中提取JSON时要对键进行符号化,则可能需要保持一致并全面使用符号。

In addition to the previous answer... 除了先前的答案...

Unfortunately, there is, to my knowledge, no method on Hash that does this in one operation. 不幸的是,据我所知,在Hash上没有一种方法可以一次完成此操作。 I've always accomplished this by brute force, as in: 我一直都是用蛮力实现的,例如:

hash[:new_key] = hash[:old_key]
hash.delete(:old_key)

A shortcut for this, suggested in the comment below by "mu is too short", is: 在下面的注释中,“ mu is too short”建议的快捷方式是:

hash[:new_key] = hash.delete(:old_key)

To illustrate in irb: 在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}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM