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

发布于 2024-11-29 18:01:29 字数 335 浏览 1 评论 0 原文

我正在 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

有什么想法吗?

I am loading a YAML file in Rails 3.0.9 like this:

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

It loads the all of the contents like hierarchical hashes, no problem. The part I don't like is the fact that the hashes can only be accessed with single or double quotes but not a symbol.

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

Any thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

忘东忘西忘不掉你 2024-12-06 18:01:29

尝试使用 HashWithIn DifferentAccess

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

Try using the HashWithIndifferentAccess like

APP_CONFIG = HashWithIndifferentAccess.new(YAML.load(File.read(File.expand_path('../app.yml', __FILE__))))
成熟的代价 2024-12-06 18:01:29

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

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 肯定不会支持键合并,正如我在示例中所示的那样。)

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

An alternative solution is to have the keys which you wish to access as a symbol prepended with a colon. For example:

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

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default

Later you can then access these like so:

APP_CONFIG[:symbol]
APP_CONFIG['string']

Note that I am using YAML::ENGINE.yamler = "syck". Not sure if this works with psych. (Psych definitely won't support key merging as I showed in the example though.)

About using HashWithIndifferentAccess: using it has the side effect of creating duplicate keys: one for symbol access and one for string access. This might be nefarious if you pass around YAML data as arrays. Be aware of this if you go with that solution.

壹場煙雨 2024-12-06 18:01:29

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

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

If you are working in Ruby on Rails, You might want to take a look at symbolize_keys(), which does exactly what the OP asked for. If the hash is deep,you can use deep_symbolize_keys(). Using this approach, the answer is

APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__))).deep_symbolize_keys
她比我温柔 2024-12-06 18:01:29

Psych(又名 YAML)提供关键字参数 :symbolize_names 将键加载为符号。 查看方法参考

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

Psych (a.k.a. YAML) provides the keyword argument :symbolize_names to load keys as symbols. 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)
邮友 2024-12-06 18:01:29

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

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

This is the same from the selected answer, but with a better syntax:

YAML.load(File.read(file_path)).with_indifferent_access 
以酷 2024-12-06 18:01:29

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

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

--- !map:HashWithIndifferentAccess

然后像平常一样简单地 YAML.load 。唯一的技巧是,如果您在环境中执行此操作以用于初始化程序等(就像我一样),则需要已经加载 Rails。

There is another potential answer I discovered while digging around.

You can forgo HashWithIndifferentAccess.new by instead adding this to the top of your YAML files:

--- !map:HashWithIndifferentAccess

then simply YAML.load like normal. The only trick is that rails needs to already be loaded if you are doing this in your environment for use in initializers, etc. (like I am).

过气美图社 2024-12-06 18:01:29
  1. Rails 有一种特殊的方法来符号化键。
  2. 您可以使用 load_file 方法并摆脱 File.read
  3. 不确定是否还需要expand_path,默认目录是rails root。

我会写得这么简单:

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

  1. Rails has a special method to symbolize keys.
  2. You can use load_file method and get rid of File.read
  3. Not sure if you need expand_path also, the default directory is rails root.

I'd write it that simple:

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

疑心病 2024-12-06 18:01:29

只需在 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

Just use appropriate option in your YAML parser. For instance, symbolize_names in Psych:

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

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

夏天碎花小短裙 2024-12-06 18:01:29

如果您使用纯 Ruby(即没有 Rails),您可以中间更改为 JSON 格式。 JSON 库的 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。

If you're using pure Ruby (i.e. no Rails), you could intermediately change to JSON format. The JSON lib's parse method can symbolize keys.

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

Here's what I mean:

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

Note: This adds overhead of conversion to and from json.

辞慾 2024-12-06 18:01:29

您可能已经习惯了 Rails 中的 params hash,它实际上是一个 HashWithIn DifferentAccess 而不是标准的 ruby​​ Hash 对象。这允许您使用“action”等字符串或“:action”等符号来访问内容。

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

因此,要使用 YAML 进行此操作,您必须将 YAML.load 的结果加载到 HashWithIn DifferentAccess 中,如下所示:

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

You are probably used to the params hash in Rails, which is actually a HashWithIndifferentAccess rather than a standard ruby Hash object. This allows you to use either strings like 'action' or symbols like :action to access the contents.

With a HashWithIndifferentAccess, you will get the same results regardless of what you use, but keep in mind this only works on HashWithIndifferentAccess objects.

So to make this work with YAML, you'll have to load the result of YAML.load into a HashWithIndifferentAccess, like so:

APP_CONFIG = HashWithIndifferentAccess.new(   YAML.load(File.read(File.expand_path('../app.yml', __FILE__)))   )
她比我温柔 2024-12-06 18:01:29

我通常不会使用 HashWithIn DifferentAccess 只是为了避免混淆并防止访问方式不一致,所以我会做的是附加 .deep_symbolize_keys 来获取整个事情都是符号键形式的。

I usually don't use HashWithIndifferentAccess just to avoid confusion and prevent inconsistencies in the way that it is accessed, so what I would do instead is tack on a .deep_symbolize_keys to get the whole thing in symbol key form.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文