Rails load YAML to hash and reference by symbol

51,921

Solution 1

Try using the HashWithIndifferentAccess like

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

Solution 2

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.

Solution 3

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

Solution 4

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

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

Solution 5

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)
Share:
51,921
Michael K Madison
Author by

Michael K Madison

Updated on July 05, 2022

Comments

  • Michael K Madison
    Michael K Madison almost 2 years

    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?

  • Michael K Madison
    Michael K Madison almost 13 years
    Thanks a million Rob. only trick was in making sure Rails was already loaded.
  • streetlogics
    streetlogics almost 10 years
    deep_symbolize_keys() should handle nested attributes.
  • Nickolay Kondratenko
    Nickolay Kondratenko about 9 years
    Looks fine but I don't use ActiveSupport
  • Nickolay Kondratenko
    Nickolay Kondratenko about 9 years
    Good solution but it is the part of ActiveSupport. But it works in case of using Rails
  • Chris Nicola
    Chris Nicola over 8 years
    This should really be the correct answer. It is likely not obvious to anyone that YAML properties are not parsed as symbols by default.
  • Eduardo Santana
    Eduardo Santana about 2 years
    If the file has an Array of hashes it won't work, because with_indifferent_access doesn't apply to arrays.