【问题标题】:How to rename a symbol in hash parameters?如何重命名哈希参数中的符号?
【发布时间】:2023-03-05 13:54:02
【问题描述】:

我有来自外部 API 的参数,这些参数使用 CamelCase 格式化 JSON 响应,我想将其放入我的 Rails 应用程序中:

{"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 将作为参数干净地返回到我的数据库中,以允许干净的保存界面,例如:

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

但是我在转换 :account_id 时遇到了问题,因为该参数与我的数据库的主键冲突。

为了解决这个问题,我的想法是将params[:account_id] 的所有符号实例转换为params[:account_key_id],这样这些参数就不会与我的数据库现有的account_id 字段冲突。

我该怎么做,有没有比我在这里描述的更好的方法来使用外部 JSON API?

【问题讨论】:

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


    【解决方案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 从数据库中提取出来时对键进行符号化,那么您可能希望保持一致并全面使用符号。

    【讨论】:

      【解决方案2】:

      除了上一个答案...

      不幸的是,据我所知,在 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}
      

      【讨论】:

      • Hash#delete 方便地返回已删除键的值,因此您可以说 hash[:new_key] = hash.delete(:old_key)
      猜你喜欢
      • 2014-10-04
      • 2014-03-26
      • 2013-07-20
      • 2013-04-28
      • 2014-10-06
      • 1970-01-01
      • 2017-02-19
      • 2015-06-16
      • 1970-01-01
      相关资源
      最近更新 更多