Rails加载YAML以哈希并按符号引用

时间:2011-08-16 02:25:25

标签: ruby-on-rails hash yaml symbols

我在Rails 3.0.9中加载一个YAML文件,如下所示:

APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__)))

它加载所有内容,如分层哈希,没问题。我不喜欢的部分是哈希只能用单引号或双引号访问而不能用符号访问。

APP_CONFIG['mailer']['username']  # works fine
APP_CONFIG[:mailer][:username]    # doesn't

有什么想法吗?

11 个答案:

答案 0 :(得分:74)

尝试使用HashWithIndifferentAccess之类的

APP_CONFIG = HashWithIndifferentAccess.new(YAML.load(File.read(File.expand_path('../app.yml', __FILE__))))

答案 1 :(得分:33)

另一种解决方案是将您希望访问的键作为带有冒号的符号进行访问。例如:

default: &default
  :symbol: "Accessed via a symbol only"
  string: "Accessed via a string only"

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default

稍后您可以像这样访问这些:

APP_CONFIG[:symbol]
APP_CONFIG['string']

请注意,我使用的是YAML::ENGINE.yamler = "syck"。不确定这是否适用于psych。 (尽管如我在示例中所示,Psych肯定不会支持键合并。)

关于使用HashWithIndifferentAccess使用它具有创建重复键的副作用:一个用于符号访问,另一个用于字符串访问。如果您将YAML数据作为数组传递,这可能是邪恶的。如果你使用该解决方案,请注意这一点。

答案 2 :(得分:26)

如果您使用的是Ruby on Rails,您可能需要查看symbolize_keys(),它正是OP所要求的。如果哈希很深,您可以使用deep_symbolize_keys()。使用这种方法,答案是

APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__))).deep_symbolize_keys

答案 3 :(得分:16)

这与所选答案相同,但语法更好:

YAML.load(File.read(file_path)).with_indifferent_access 

答案 4 :(得分:11)

我在挖掘时发现了另一个潜在的答案。

您可以放弃HashWithIndifferentAccess.new,而不是将其添加到YAML文件的顶部:

--- !map:HashWithIndifferentAccess

然后就像正常的YAML.load一样。唯一的技巧是如果你在你的环境中这样做以便在初始化器等中使用,就需要加载rails(就像我一样)。

答案 5 :(得分:7)

  1. Rails有一种特殊的方法来对符号进行符号化。
  2. 您可以使用load_file方法并删除File.read
  3. 不确定是否还需要expand_path,默认目录为rails root。
  4. 我写得那么简单:

    YAML::load_file('app.yml').symbolize_keys

答案 6 :(得分:2)

你可能习惯于Rails中的params哈希,它实际上是一个HashWithIndifferentAccess而不是标准的ruby Hash对象。这允许您使用像'action'这样的字符串或像:action来访问内容。

使用HashWithIndifferentAccess,无论使用什么,都会得到相同的结果,但请记住,这只适用于HashWithIndifferentAccess对象。

所以为了使这个工作与YAML一起使用,你必须将YAML.load的结果加载到HashWithIndifferentAccess中,如下所示:

APP_CONFIG = HashWithIndifferentAccess.new(   YAML.load(File.read(File.expand_path('../app.yml', __FILE__)))   )

答案 7 :(得分:2)

如果您使用纯Ruby(即没有Rails),则可以中间更改为JSON格式。 JSON lib的parse方法可以对键进行符号化。

http://ruby-doc.org/stdlib-2.0.0/libdoc/json/rdoc/JSON.html#method-i-parse

这就是我的意思:

JSON.parse(JSON.dump(YAML.load_file(File.expand_path('../app.yml', __FILE__))), symbolize_names: true)

注意:这会增加与json的转换开销。

答案 8 :(得分:1)

Psych(亦称YAML)提供关键字参数:symbolize_names来将键作为符号加载。 See method reference

file_path = File.expand_path('../app.yml', __FILE__)
yaml_contents = File.read(file_path)

APP_CONFIG = YAML.safe_load(yaml_contents, symbolize_names: true)

答案 9 :(得分:0)

我通常不使用HashWithIndifferentAccess只是为了避免混淆并防止访问方式的不一致,所以我要做的是改为.deep_symbolize_keys以获取整个事物符号键形式。

答案 10 :(得分:0)

只需在您的YAML解析器中使用适当的选项即可。例如,《 Psych》中的symbolize_names

APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__)), symbolize_names: true)

请参阅RDoc:https://ruby-doc.org/stdlib-2.6.1/libdoc/psych/rdoc/Psych.html#method-c-load