Вызовите Project.Endpoint.static_url() в файле конфигурации

#elixir #phoenix-framework #dry

#elixir #phoenix-framework #dry

Вопрос:

Мне нужно настроить протокол 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:

Прежде всего, вы должны знать, что 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 , но тогда вам нужно позаботиться об объединении значений самостоятельно.

Комментарии:

1. Отличный ответ! Это действительно продвинуло меня на шаг вперед в Elixir / Phoenix. 🙂