如何优雅地symbolize_keys为'嵌套'哈希

SHS*_*SHS 47 ruby hash ruby-on-rails dry

请考虑以下代码:

  hash1 = {"one" => 1, "two" => 2, "three" => 3}
  hash2 = hash1.reduce({}){ |h, (k,v)| h.merge(k => hash1) }
  hash3 = hash2.reduce({}){ |h, (k,v)| h.merge(k => hash2) }
  hash4 = hash3.reduce({}){ |h, (k,v)| h.merge(k => hash3) }
Run Code Online (Sandbox Code Playgroud)

hash4是一个'嵌套'哈希,即带有字符串键的散列和类似的'嵌套'哈希值.

Hails in Rails的'symbolize_keys'方法让我们可以轻松地将字符串键转换为符号.但我正在寻找一种优雅的方法将所有键(主键加上hash4中所有哈希的键)转换为符号.

重点是从我的(imo)丑陋的解决方案中解脱出来:

  class Hash
    def symbolize_keys_and_hash_values
      symbolize_keys.reduce({}) do |h, (k,v)|
        new_val = v.is_a?(Hash) ? v.symbolize_keys_and_hash_values : v
        h.merge({k => new_val})
      end
    end
  end

  hash4.symbolize_keys_and_hash_values #=> desired result
Run Code Online (Sandbox Code Playgroud)

仅供参考:安装程序是Rails 3.2.17和Ruby 2.1.1

更新:

答案是hash4.deep_symbolize_keys针对Rails <= 5.0

答案是JSON.parse(JSON[hash4], symbolize_names: true)针对Rails> 5

jvn*_*ill 97

有几种方法可以做到这一点

  1. deep_symbolize_keysRails中有一个方法,但Rails 5.1中不推荐这样做

    hash.deep_symbolize_keys!

  2. 正如@chrisgeeq所提到的,deep_transform_keysRails 4提供了一种方法.

    hash.deep_transform_keys(&:to_sym)

    还有一个爆炸!版本来替换现有对象.

  3. 还有另一种方法叫做with_indifferent_access.这允许您使用字符串或符号(如params控制器中的方式)访问哈希.这种方法没有爆炸对应物.

    hash = hash.with_indifferent_access

  4. 最后一个是使用JSON.parse.我个人不喜欢这个,因为你正在进行2次转换 - 哈希到json然后json到哈希.

    JSON.parse(JSON[h], symbolize_names: true)

更新:

16/01/19 - 添加更多选项并注意deep_symbolize_keys的弃用


Mik*_*ski 25

您不能将此方法用于params或任何其他任何实例ActionController::Parameters,因为deep_symbolize_keys出于安全原因,Rails 5.0+中的方法已被弃用,并且将在Rails 5.1+中删除,因为ActionController::Parameters不再继承Hash

所以@Uri Agassi的这种方法似乎是普遍的方法.

JSON.parse(JSON[h], symbolize_names: true)
Run Code Online (Sandbox Code Playgroud)

但是,Rails Hash对象仍然拥有它.

所以选项是:

  • 它已经在`ActionController :: Parameters`上弃用了(正如[本期](https://github.com/activeadmin-plugins/active_admin_import/issues/91)所暗示的那样),但不像我上面所说的"哈希".正如你的引语所说,*`ActionController :: Parameters`不再继承hash*.这个问题是关于"哈希". (3认同)

Ale*_*der 6

在rails中,您可以创建HashWithIndifferentAccess类.创建此类的实例,将您的哈希传递给它的构造函数,然后使用符号或字符串的键(如Controller的Actions的参数)访问它:

hash = {'a' => {'b' => [{c: 3}]}}

hash = hash.with_indifferent_access
# equal to:
# hash = ActiveSupport::HashWithIndifferentAccess.new(hash)

hash[:a][:b][0][:c]

=> 3
Run Code Online (Sandbox Code Playgroud)