Вызовите Project.Endpoint.static_url () в файле конфигурации - PullRequest
1 голос
/ 28 марта 2019

Мне нужно настроить протокол OAuth, и логическое место для этого находится в пределах /config/dev.exs, не так ли?

Прямо выше, я настраиваю Endpoint.Так что в моем приложении я могу написать Project.Endpoint.static_url() и получить, например.http://localhost:4000.

Каким будет СУХОЙ способ получить это значение в конфигурации?

config :project, Project.Endpoint,
  http: [port: 4000],
  url: [scheme: "http", host: "localhost", port: 4000]

config :project, authentication: [
    client_id: System.get_env("CLIENT_ID"),
    client_secret: System.get_env("CLIENT_SECRET"),
    site: "https://example.com",
    authorize_url: "/connexion/oauth2/authorize",
    redirect_uri: "http://localhost:4000/oauth/callback"
    # This version fails: Project.Endpoint.static_url/0 is undefined (module Project.Endpoint is not available)
    # redirect_uri: "#{Project.Endpoint.static_url()}/oauth/callback"
  ]

Спасибо

1 Ответ

1 голос
/ 28 марта 2019

Прежде всего вы должны знать, что Elixir будет разрешать файлы конфигурации во время компиляции, что означает, что System.get_env будет оцениваться при компиляции вашего приложения. В скомпилированном коде значения будут фиксированными.

Команда Elixir работает над упрощением этого процесса, но на данный момент предложенный способ обойти это - отложить чтение переменных среды до запуска вашего приложения.

Обычно это можно сделать в модуле приложения перед запуском дочерних элементов, вызвав Application.put_env/3-4 и введя значения, прочитанные из System.get_env.

Некоторые библиотеки, такие как Ecto, также предоставляют обратные вызовы init, которые позволяют подключаться к процессу загрузки для динамической настройки. Смотри https://hexdocs.pm/ecto/Ecto.Repo.html#module-urls

Тогда это также место, где можно избавиться от дублирования. В конце концов, конфигурация - это просто код Elixir, и вы можете просто установить значения, основанные на других, как и следовало ожидать:

defmodule Project.Application do
  use Application

  def start(_type, _args) do
    Application.put_env :project, authentication: [
      redirect_uri: "#{Project.Endpoint.static_url()}/oauth/callback",
      ...
    ]

    children = [
      Project.Repo,
      ProjectWeb.Endpoint,
      ...
    ]
    opts = [strategy: :one_for_one, name: Project.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Вы также можете смешивать и сочетать как конфигурационный файл, так и Application.put_env, но тогда вам нужно позаботиться о слиянии значений самостоятельно.

...