指定模块名称时如何访问配置相关键
How to access Config related keys when a module name is specified
查看 phoenix 中的配置文件时,如果我创建这样的配置:
config :myapp,
http: 4000
我可以像这样在我的代码中引用该键:
Application.fetch_env!(:myapp, :http)
有时配置似乎是特定于某个模块的,例如下面有 MyApp.Endpoint.
这只是将配置分成几部分吗?如果我也需要,如何在我的代码中引用下面的 http 端口?
config :myapp, MyApp.Endpoint,
http: [port: 4000],
debug_errors: true
在这种情况下,您从 fetch_env!/2
调用中返回的是 keyword list。您可以像使用地图一样访问它:
Application.fetch_env!(:myapp, :http)[:port]
或者将其转换为 Map,然后这样做:
Application.fetch_env!(:myapp, :http) |> Map.new |> Map.get(:port)
编辑 - 基于@BrettBeatty 的评论
您也可以使用Keyword.get/2
函数:
:myapp |> Application.get_env(:http) |> Keyword.get(:port)
Sometimes the config seems to be specific to a module, like the below
has MyApp.Endpoint.
Is this just breaking up the config into sections kind of?
tldr;
是的。使用您的配置文件,您可以创建如下内容:
[
{:ecto_repos, [MyApp.Repo]},
{.Repo,
[
username: "postgres",
password: "postgres",
database: "myapp_dev",
hostname: "localhost",
pool_size: 10
]},
{:http, [port: 4000]}, <===**** HERE ****
{:included_applications, []},
{MyAppWeb.Endpoint, <====**** HERE ****
[
url: [host: "localhost"],
secret_key_base: "rchq5yMDPqqEBzFR+wIoqpc+kNquiyNDYUp/K8aF2Yj6POl/gjfj0H0rljE06LI5",
render_errors: [view: MyAppWeb.ErrorView, accepts: ["html", "json"]],
pubsub: [name: Rum.PubSub, adapter: Phoenix.PubSub.PG2],
http: [port: 4000],
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: [
node: [
"node_modules/webpack/bin/webpack.js",
"--mode",
"development",
"--watch-stdin",
{:cd, "/Users/7stud/phoenix_apps/book/myapp/assets"}
]
],
live_reload: [
patterns: [~r/priv\/static\/.*(js|css|png|jpeg|jpg|gif|svg)$/,
~r/priv\/gettext\/.*(po)$/, ~r/lib\/myapp_web\/views\/.*(ex)$/,
~r/lib\/myapp_web\/templates\/.*(eex)$/]
]
]},
How do I
reference the http port like below in my code if I need too?
config :myapp, MyApp.Endpoint,
http: [port: 4000],
debug_errors: true
如果您查看该配置部分并删除换行符,您会得到:
config :myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true
而且,如果您添加一些括号,您将得到:
config(:myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true)
这是一个函数调用,第一个参数是:myapp
,第二个参数是MyApp.Endpoint
,然后这部分:
http: [port: 4000], debug_errors: true
是一个Keyword list
。跑题了……在elixir中,可以这样定义函数:
def go(x, y, z) do
IO.puts x
IO.puts y
IO.inspect z
end
并这样称呼它们:
My.go(10, 20, a: 1, b: 2)
这将输出:
10
20
[a: 1, b: 2]
这表明,如果函数调用中的最后一个参数具有特定语法,那么最后一个参数将全部收集到称为 Keyword list
的东西中,并作为一个参数传递给函数。因此,即使看起来您在调用 My.go()
时带有四个参数,但您实际上是在用三个参数调用它。
因此,这个函数调用:
config(:myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true)
正在调用 config/3
函数定义。
为什么在配置文件中没有定义 config/3
函数的情况下可以调用这样的函数?这一行:
use Mix.Config
将 config/3
函数定义注入到文件中。这是 elixir 的一个问题:发生了很多神奇的事情,这使得很难弄清楚函数定义的来源。
此时,您知道在配置文件中调用了一个config/3
函数:
config :myapp, MyApp.Endpoint,
http: [port: 4000],
debug_errors: true
此外,配置文件顶部的 use Mix.Config
行暗示该模块中可能定义了 config/3
,因此您可以仔细阅读 Mix.Config docs。果然,文档中描述了一个 config/3
函数。文档中还描述了一个 config/2
函数,在这里调用:
config :myapp,
http: 4000
如果您阅读 config/2
的文档,似乎很容易理解它是如何工作的:当您使用 config/2
设置键和值时,您可以检索与键关联的特定值呼叫:
Application.get_env(:myapp, key)
例如,
Application.get_env(:myapp, :http)
#=> 4000
但是,当您使用 config/3
设置键和值时,您无法检索与键关联的特定值——相反,您最终会检索 key/value 对的整个列表:
keyword_list = Application.get_env(:myapp, module)
config/3
创建一个嵌套结构,其中模块是键,它的值是由您在配置文件中指定的 key/value 对组成的关键字列表,例如:
http: [port: 4000],
debug_errors: true
另一种解决问题的方法是考虑嵌套映射:
%{
myapp: %{
http: 4000, #<== config/2
my_app_endpoint: %{http: [port: 4000, debug_errors: true]} #<== config/3
}
...而Application.get_env()
只允许指定两个key,如:
Application.get_env(:myapp, :http) #=> 4000
或:
Application.get_env(:myapp, :my_app_endpoint) #=> %{http: [port: 4000, debug_errors: true]}
检索 keyword_list 后:
keyword_list = Application.get_env(:myapp, module)
然后您必须使用您对 elixir 的一般知识从关键字列表中检索与特定键关联的值:
all = Application.get_all_env(:myapp)
IO.inspect all #=> lots of stuff (which is not a keyword list)
keyword_list = Application.get_env(:myapp, MyApp.Endpoint)
IO.inspect keyword_list #=> a keyword list with lots of key/value pairs
http = Keyword.get(keyword_list, :http)
IO.inspect http #=> [port: 4000]
port = Keyword.get(http_keyword_list, :port)
IO.inspect port #=>4000
查看 phoenix 中的配置文件时,如果我创建这样的配置:
config :myapp,
http: 4000
我可以像这样在我的代码中引用该键:
Application.fetch_env!(:myapp, :http)
有时配置似乎是特定于某个模块的,例如下面有 MyApp.Endpoint.
这只是将配置分成几部分吗?如果我也需要,如何在我的代码中引用下面的 http 端口?
config :myapp, MyApp.Endpoint,
http: [port: 4000],
debug_errors: true
在这种情况下,您从 fetch_env!/2
调用中返回的是 keyword list。您可以像使用地图一样访问它:
Application.fetch_env!(:myapp, :http)[:port]
或者将其转换为 Map,然后这样做:
Application.fetch_env!(:myapp, :http) |> Map.new |> Map.get(:port)
编辑 - 基于@BrettBeatty 的评论
您也可以使用Keyword.get/2
函数:
:myapp |> Application.get_env(:http) |> Keyword.get(:port)
Sometimes the config seems to be specific to a module, like the below has MyApp.Endpoint.
Is this just breaking up the config into sections kind of?
tldr;
是的。使用您的配置文件,您可以创建如下内容:
[
{:ecto_repos, [MyApp.Repo]},
{.Repo,
[
username: "postgres",
password: "postgres",
database: "myapp_dev",
hostname: "localhost",
pool_size: 10
]},
{:http, [port: 4000]}, <===**** HERE ****
{:included_applications, []},
{MyAppWeb.Endpoint, <====**** HERE ****
[
url: [host: "localhost"],
secret_key_base: "rchq5yMDPqqEBzFR+wIoqpc+kNquiyNDYUp/K8aF2Yj6POl/gjfj0H0rljE06LI5",
render_errors: [view: MyAppWeb.ErrorView, accepts: ["html", "json"]],
pubsub: [name: Rum.PubSub, adapter: Phoenix.PubSub.PG2],
http: [port: 4000],
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: [
node: [
"node_modules/webpack/bin/webpack.js",
"--mode",
"development",
"--watch-stdin",
{:cd, "/Users/7stud/phoenix_apps/book/myapp/assets"}
]
],
live_reload: [
patterns: [~r/priv\/static\/.*(js|css|png|jpeg|jpg|gif|svg)$/,
~r/priv\/gettext\/.*(po)$/, ~r/lib\/myapp_web\/views\/.*(ex)$/,
~r/lib\/myapp_web\/templates\/.*(eex)$/]
]
]},
How do I reference the http port like below in my code if I need too?
config :myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true
如果您查看该配置部分并删除换行符,您会得到:
config :myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true
而且,如果您添加一些括号,您将得到:
config(:myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true)
这是一个函数调用,第一个参数是:myapp
,第二个参数是MyApp.Endpoint
,然后这部分:
http: [port: 4000], debug_errors: true
是一个Keyword list
。跑题了……在elixir中,可以这样定义函数:
def go(x, y, z) do
IO.puts x
IO.puts y
IO.inspect z
end
并这样称呼它们:
My.go(10, 20, a: 1, b: 2)
这将输出:
10
20
[a: 1, b: 2]
这表明,如果函数调用中的最后一个参数具有特定语法,那么最后一个参数将全部收集到称为 Keyword list
的东西中,并作为一个参数传递给函数。因此,即使看起来您在调用 My.go()
时带有四个参数,但您实际上是在用三个参数调用它。
因此,这个函数调用:
config(:myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true)
正在调用 config/3
函数定义。
为什么在配置文件中没有定义 config/3
函数的情况下可以调用这样的函数?这一行:
use Mix.Config
将 config/3
函数定义注入到文件中。这是 elixir 的一个问题:发生了很多神奇的事情,这使得很难弄清楚函数定义的来源。
此时,您知道在配置文件中调用了一个config/3
函数:
config :myapp, MyApp.Endpoint,
http: [port: 4000],
debug_errors: true
此外,配置文件顶部的 use Mix.Config
行暗示该模块中可能定义了 config/3
,因此您可以仔细阅读 Mix.Config docs。果然,文档中描述了一个 config/3
函数。文档中还描述了一个 config/2
函数,在这里调用:
config :myapp,
http: 4000
如果您阅读 config/2
的文档,似乎很容易理解它是如何工作的:当您使用 config/2
设置键和值时,您可以检索与键关联的特定值呼叫:
Application.get_env(:myapp, key)
例如,
Application.get_env(:myapp, :http)
#=> 4000
但是,当您使用 config/3
设置键和值时,您无法检索与键关联的特定值——相反,您最终会检索 key/value 对的整个列表:
keyword_list = Application.get_env(:myapp, module)
config/3
创建一个嵌套结构,其中模块是键,它的值是由您在配置文件中指定的 key/value 对组成的关键字列表,例如:
http: [port: 4000],
debug_errors: true
另一种解决问题的方法是考虑嵌套映射:
%{
myapp: %{
http: 4000, #<== config/2
my_app_endpoint: %{http: [port: 4000, debug_errors: true]} #<== config/3
}
...而Application.get_env()
只允许指定两个key,如:
Application.get_env(:myapp, :http) #=> 4000
或:
Application.get_env(:myapp, :my_app_endpoint) #=> %{http: [port: 4000, debug_errors: true]}
检索 keyword_list 后:
keyword_list = Application.get_env(:myapp, module)
然后您必须使用您对 elixir 的一般知识从关键字列表中检索与特定键关联的值:
all = Application.get_all_env(:myapp)
IO.inspect all #=> lots of stuff (which is not a keyword list)
keyword_list = Application.get_env(:myapp, MyApp.Endpoint)
IO.inspect keyword_list #=> a keyword list with lots of key/value pairs
http = Keyword.get(keyword_list, :http)
IO.inspect http #=> [port: 4000]
port = Keyword.get(http_keyword_list, :port)
IO.inspect port #=>4000