Elixir Phoenix 插头及其放置位置

Elixir Phoenix Plugs and where to place them

我目前正在学习 Elixir Phoenix 框架。我现在卡在https://hexdocs.pm/phoenix/routing.html#forward,是关于如何使用forward命令。

那里写着,现在没有必要了解 Plugs,所以如果我想尝试那个 forward 命令,我可以将他们的 Plug 实现复制到我的应用程序中。但具体在哪里?我试图搜索它并尝试使用我找到的东西,但我做错了。

这是我的 .\lib\hello_web\router.ex 文件中的范围:

scope "/", HelloWeb do
  pipe_through :browser # Use the default browser stack

  get "/", PageController, :index
  forward "/jobs", BackgroundJob.Plug, name: "Hello, Phoenix"
end

这是插件的代码:

defmodule BackgroundJob.Plug do
  def init(opts), do: opts
  def call(conn, opts) do
    conn
    |> Plug.Conn.assign(:name, Keyword.get(opts, :name, "Background Job"))
    |> BackgroundJob.Router.call(opts)
  end
end

defmodule BackgroundJob.Router do
  use Plug.Router

  plug :match
  plug :dispatch

  get "/", do: send_resp(conn, 200, "Welcome to #{conn.assigns.name}")
  get "/active", do: send_resp(conn, 200, "5 Active Jobs")
  get "/pending", do: send_resp(conn, 200, "3 Pending Jobs")
  match _, do: send_resp(conn, 404, "Not found")
end

此时我应该对 Plugs 和 Phoenix 几乎一无所知,所以这可能是显而易见的事情,但我真的在那里呆了几个小时。谁能帮我找出该代码的放置位置?

欢迎使用 Whosebug。

你没有发布你遇到的错误,但我猜你的问题是模块命名。在 phoenix 中,在 scope 块内使用的模块将以您作为该范围的参数提供的模块名称为前缀(在本例中为 HelloWeb)。因此,将插件模块的名称更改为 HelloWeb.BackgroundJob.Plug 应该就足够了。或者,您不能将作用域模块传递给 scope:

scope "/" do
  pipe_through :browser # Use the default browser stack

  get "/", HelloWeb.PageController, :index
  forward "/jobs", BackgroundJob.Plug, name: "Hello, Phoenix"
end

请注意本例中的更改 PageController -> HelloWeb.PageController

就放置位置而言 - lib 中的任何 .ex 文件都可以,因为 elixir 会编译所有这些文件。事实上,您只需将代码粘贴到 router.ex 中即可快速进行测试。按照惯例,文件名应该跟在模块名称之后,所以 HelloWeb.BackgroundJob.Plug 应该位于 lib/hello_web/background_job/plug.ex.

是的,我理解你的困惑。 可以在指南中更清楚地解释它。

如果将模块名称传递给作用域,传入的模块名称将作为作用域中所有模块的前缀。

例如,假设您传入的模块名称是 HelloWeb, 当您将它传递到这样的范围时:

scope "/", HelloWeb do
  ...
  get "/", PageController, :index
  forward "/jobs", BackgroundJob.Plug
end

"/" 路由将查找 HelloWeb.PageController
"/jobs" 路线将寻找 HelloWeb.BackgroundJob.Plug

所以为了让你的错误消失,我假设是这样的:

helloweb.backgroundjob.plug.init/1 is undefined

您可以从范围中删除传入的模块名称并手动添加模块名称,保持 BackgroundJob.Plug 不变,如下所示:

scope "/",  do
  ...
  get "/", HelloWeb.PageController, :index
  forward "/jobs", BackgroundJob.Plug
end

或者,也许可以省去一些重复输入,而是添加一个“/jobs”范围,如下所示:

  scope "/", HelloWeb do
    ...
    get "/", PageController, :index
  end

  scope "/jobs" do
    forward "/", BackgroundJob.Plug, name: "Hello Phoenix"
  end

请注意,示例中的 ... 表示 pipe_through 方法和其他路线,这些方法和其他路线对于传达想法不是必需的。

希望对您有所帮助。