2011-08-16 11 views
54

wczytuję plik YAML w Rails 3.0.9 tak:Rails załadować YAML do mieszania i oznaczenie symbolem

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

ładuje wszystkie treści jak hierarchicznych skrótów, nie ma problemu. Częścią, której nie lubię, jest to, że do skrótów można uzyskać tylko pojedyncze lub podwójne cudzysłowy, ale nie symbol.

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

Jakieś myśli?

Odpowiedz

71

Spróbuj użyć HashWithIndifferentAccess jak

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

Dzięki milionowi Roba. Jedyną sztuczką było upewnienie się, że Rails został już załadowany. –

+2

Wygląda dobrze, ale nie używam ActiveSupport –

+0

<3 dziękuję człowieku! –

2

Prawdopodobnie używany do mieszania params w szynach, co jest rzeczywiście HashWithIndifferentAccess aniżeli standardowy obiekt Ruby Hash. Pozwala to na użycie ciągów takich jak "akcja" lub symboli takich jak: akcja, aby uzyskać dostęp do zawartości.

Przy pomocy HashWithIndifferentAccess, otrzymasz te same wyniki niezależnie od tego, czego używasz, ale pamiętaj, że działa to tylko na obiektach HashWithIndifferentAccess.

Więc do tej pracy z YAML, będziesz musiał załadować wynik YAML.load w HashWithIndifferentAccess, tak:

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

ładne informacje @Tilo (y) –

9

Jest inna potencjalna odpowiedź odkryłem podczas kopania wokół.

Można zrezygnować HashWithIndifferentAccess.new zamiast przez dodanie tego do góry plików YAML:

--- !map:HashWithIndifferentAccess 

po prostu YAML.load jak normalne. Jedyną sztuczką jest to, że szyny muszą być już załadowane, jeśli robisz to w swoim środowisku do użycia w inicjalizatorach itp. (Jak ja).

28

Alternatywnym rozwiązaniem jest posiadanie kluczy, do których chcesz uzyskać dostęp, jako symbolu poprzedzonego dwukropkiem. Na przykład:

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

development: 
    <<: *default 

test: 
    <<: *default 

production: 
    <<: *default 

Później można następnie uzyskać dostęp do nich tak:

APP_CONFIG[:symbol] 
APP_CONFIG['string'] 

Zauważ, że używam YAML::ENGINE.yamler = "syck". Nie wiem, czy to działa z psych. (Psych pewno nie będzie wspierać łączenie klucza jak pokazałem w przykładzie choć.)

O użyciu HashWithIndifferentAccess: stosując ma efekt uboczny tworzenia duplikatów kluczy: jeden dla dostępu symbol i jeden dla dostępu strun. Może to być niefortunne, jeśli przekażesz dane YAML jako tablice. Bądź tego świadomy, jeśli skorzystasz z tego rozwiązania.

+0

To jest to, czego potrzebuję, dzięki! –

+0

To naprawdę powinna być poprawna odpowiedź. Prawdopodobnie nie jest dla nikogo oczywiste, że właściwości YAML nie są domyślnie analizowane jako symbole. –

23

Jeśli pracujesz w Ruby on Rails, możesz rzucić okiem na symbolize_keys(), który robi dokładnie to, o co prosił OP. Jeśli skrót jest głęboki, możesz użyć deep_symbolize_keys().Stosując to podejście, odpowiedź jest

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

To nie działa dla zagnieżdżonych atrybutów. –

+6

'deep_symbolize_keys()' powinno obsłużyć zagnieżdżone atrybuty. – streetlogics

+0

Dobre rozwiązanie, ale jest to część ActiveSupport. Ale działa w przypadku korzystania z Rails –

12

To samo od wybranej odpowiedzi, ale z lepszą składnią:

YAML.load(File.read(file_path)).with_indifferent_access 
7
  1. Rails posiada specjalną metodę symbolizować klucze.
  2. Możesz użyć metody load_file i pozbyć się File.read
  3. Nie jesteś pewien czy potrzebujesz również expand_path, domyślnym katalogiem jest root rails.

chciałbym napisać to takie proste:

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

2

Jeśli używasz czystego Ruby Rails (czyli brak), można tymczasowo zmienić w formacie JSON. Metoda JSON lib's parse może symbolizować klucze.

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

Oto co mam na myśli:

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

Uwaga: To dodaje narzut konwersji do i od JSON.