在配置文件中调用 Project.Endpoint.static_url()

Call Project.Endpoint.static_url() within the config file

我需要配置 OAuth 协议,执行此操作的逻辑位置在 /config/dev.exs 内,不是吗?

在右上方,我配置了Endpoint。所以在我的应用程序中,我可以写 Project.Endpoint.static_url() 并得到例如。 http://localhost:4000

在配置中获取此值的 DRY 方法是什么?

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"
  ]

谢谢

首先您应该知道 Elixir 将在编译时解析配置文件,这意味着 System.get_env 将在编译您的应用程序时进行评估。在编译后的代码中,这些值将是固定的。

Elixir 团队正在努力简化这个过程,但目前建议的解决方法是推迟读取环境变量,直到您的应用程序启动。

一般来说,这可以在启动 children 之前在您的应用程序模块中完成,方法是调用 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,但您需要自己合并这些值。