web-dev-qa-db-ja.com

Rails YAMLを読み込み、シンボルでハッシュおよび参照する

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

何かご意見は?

63

HashWithIndifferentAccess のようなものを使用してみてください

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

別の解決策は、シンボルの前にコロンを付けてアクセスしたいキーを持つことです。例えば:

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:の使用について使用すると、重複キーを作成するという副作用があります。1つはシンボルアクセス用、もう1つは文字列アクセス用です。 YAMLデータを配列として渡す場合、これは悪意があるかもしれません。そのソリューションを使用する場合は、このことに注意してください。

33
istvanp

Ruby on Railsで作業している場合は、 symbolize_keys() をご覧ください。深く、deep_symbolize_keys()を使用できます。このアプローチを使用すると、答えは

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

これは、選択した回答と同じですが、より良い構文を使用しています。

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

掘り下げながら発見した別の潜在的な答えがあります。

代わりにYAMLファイルの先頭にこれを追加することにより、HashWithIndifferentAccess.newを省略することができます。

--- !map:HashWithIndifferentAccess

その後、通常のように単純にYAML.loadを実行します。唯一の秘isは、Railsをイニシャライザなどで使用するために環境内でこれを行う場合、既にロードされている必要があるということです。

12
  1. Railsには、キーをシンボル化する特別な方法があります。
  2. Load_fileメソッドを使用してFile.readを取り除くことができます
  3. Expand_pathも必要かどうかわからない場合、デフォルトのディレクトリはRails root。

私はそれを簡単に書くでしょう:

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

7

おそらくRailsのparamsハッシュに慣れているでしょう。これは実際には標準のRubyハッシュオブジェクトではなく、HashWithIndifferentAccessです。これにより、 'action'などの文字列または:action toコンテンツにアクセスします。

HashWithIndifferentAccessを使用すると、何を使用しても同じ結果が得られますが、これはHashWithIndifferentAccessオブジェクトでのみ機能することに注意してください。

したがって、YAMLでこれを機能させるには、次のようにYAML.loadの結果をHashWithIndifferentAccessにロードする必要があります。

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

純粋なRuby(つまりRailsなし)を使用している場合は、途中でJSON形式に変更できます。JSONlibの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との間の変換のオーバーヘッドが追加されます。

2
Nav

私は通常、混乱を避け、アクセス方法の不整合を防ぐためだけにHashWithIndifferentAccessを使用しません。そのため、代わりに.deep_symbolize_keys全体をシンボルキー形式で取得します。

0
lobati