2016-04-19 13 views
9

Sembra che il modo in cui vengono caricati e compilati i file di configurazione in phoenix costituisca un problema quando si utilizzano moduli di terze parti in config.exs o dev.exs/prod.exs/test.exs.Elixir/Phoenix: come utilizzare i moduli di terze parti nei file di configurazione?

Esempio: per impostare Guardian per l'autenticazione JWT, sto tentando di utilizzare il modulo JOSE.JWK per la creazione/caricamento JWK nel mio config.exs. Posso usare il modulo nella console con iex -S mix phoenix.server. È ovviamente installato come dipendenza. L'errore che sto ricevendo è

** (Mix.Config.LoadError) could not load config config/config.exs 
    ** (UndefinedFunctionError) undefined function JOSE.JWK.from_file/2 (module JOSE.JWK is not available) 

Questo è il codice nelle mie config.exs

# Configure Guardian for JWT Authentication 
config :guardian, Guardian, 
    allowed_algos: ["HS512"], # optional 
    verify_module: Guardian.JWT, # optional 
    issuer: "MyApp", 
    ttl: { 30, :days }, 
    verify_issuer: true, # optional 
    secret_key: System.get_env("GUARDIAN_KEY_PASSPHRASE") |> JOSE.JWK.from_file(System.get_env("GUARDIAN_KEY_FILE")), 
    serializer: MyApp.GuardianSerializer 

Funziona quando mi avvolgo la chiamata a JOSE.JWK.from_file/2 in una funzione anonima. Ma, naturalmente, il valore della Guardian.config (: SECRET_KEY) è quindi la stessa funzione anonima e non il suo valore di ritorno:

# Configure Guardian for JWT Authentication 
config :guardian, Guardian, 
    allowed_algos: ["HS512"], # optional 
    verify_module: Guardian.JWT, # optional 
    issuer: "MyApp", 
    ttl: { 30, :days }, 
    verify_issuer: true, # optional 
    secret_key: fn -> System.get_env("GUARDIAN_KEY_PASSPHRASE") |> JOSE.JWK.from_file(System.get_env("GUARDIAN_KEY_FILE")) end, 
    serializer: MyApp.GuardianSerializer 

Questo è ok in questo esempio, dal Guardiano accetta una funzione per questo valore di configurazione. Ma posso immaginare altre situazioni in cui questo potrebbe essere un problema.

Questa limitazione è di proposito? Mi sto perdendo qualcosa? C'è un modo per aggirare questo?

risposta

13

Poiché la configurazione viene valutata prima della compilazione delle dipendenze, non è possibile utilizzare il codice dalle dipendenze nella configurazione.

Il motivo è semplice: la configurazione può cambiare la modalità di compilazione di una dipendenza. È necessario decidere cosa fare prima - compilare per valutare le configurazioni. È stata presa la decisione di valutare prima la configurazione poiché è molto più utile (e frequente) manipolare la compilazione attraverso le configurazioni piuttosto che utilizzare le dipendenze per configurare altre applicazioni - la maggior parte delle volte la configurazione è solo dati grezzi.

+0

La stessa domanda si applica all'accesso alle funzioni dall'app stessa, piuttosto che a una dipendenza. Questo sta causando dolore a https://github.com/trenpixster/addict/issues/105 –

+0

Sei sicuro? Come funziona 'config: my_app, MyApp.Endpoint,' funziona? – asiniy

+0

@asiniy 'MyApp.Endpoint' è solo un atomo. Se fosse 'MyApp.Endpoint.foo()', sarebbe una chiamata di funzione e avrebbe bisogno di compilare il modulo dipendente. – Emil

1

Se si compila prima un modulo che vive al di fuori di elixirc_paths prima di eseguire il mix ed è nel percorso di ricerca dell'elisir, lo troverà. Basta fare Whatever.foo(:bar)

Avrebbe più senso concludere la pre-compilazione come attività mista e chiamare il mix per assicurarsi che le configurazioni siano aggiornate prima di chiamare un dep di terze parti.

Sarebbe utile se ci fosse un hook di mix pre-config e/o uno config/lib che è precompilato prima di valutare la configurazione. In caso contrario, le configurazioni cresceranno e diventeranno pile di codice disgustose, anche se si utilizza import_config che non consente la modularizzazione e l'eliminazione del codice.

Un altro hackaround è di avere un missaggio minimale che carica abbastanza della tua app per ottenere valori e scriverli su stdout, e quindi utilizzare una porta per portarli altrove dove necessario (Rails lo fa in alcuni punti).

Problemi correlati