在哪里放置共享控制器代码

时间:2016-12-20 04:53:10

标签: elixir phoenix-framework

我有一个共享控制器功能,我想在控制器之间重复使用:

  def render_unprocessable_entity(conn, changeset) do
    conn
    |> put_status(:unprocessable_entity)
    |> render(ExampleApp.ChangesetView, "error.json", changeset: changeset)
  end

问题:我可以在哪里放这个?我试图把它放到控制器/助手/ controller_helper.ex中,它说:undefined function put_status/2。我不能在此助手中添加use ExampleApp.Web, :controller,因为它会与现有控制器冲突。我可以将它用作常规模块并使用别名,但是到处都是ControllerHelper的更多输入。

我可以把它放到web.ex中吗?但也许我不应该让那个文件太大?

干扰代码的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

使用Kernel.SpecialForms.import/2从所需模块导入所有导出的(公共)函数(在此特定情况下来自帮助程序),而不使用显式命名空间:

controller_helper.ex (或任何其他模块)

defmodule My.ControllerHelper do
  def put_status(param), do: IO.puts(param) # whatever
end

my_controller.ex (或任何其他模块)

import My.ControllerHelper # ⇐ HERE !!!

defmodule My.Controller do
  use Waveia.Web, :controller

  def render_unprocessable_entity(conn, changeset) do
    conn
    |> put_status(:unprocessable_entity) # ⇐ HERE !!!
    |> render(...)
  end
  ...
end

您是否希望从单个模块访问所有使用的模块,您可以覆盖__using__/2回调以导入模块,即调用use Helper

这样的例子是:

defmodule ExampleApp.ControllerHelper do
  defmacro __using__(opts) do
    quote do
      defp render_unprocessable_entity(conn, changeset) do
        conn
        |> put_status(:unprocessable_entity)
        |> render(ExampleApp.ChangesetView, "error.json", changeset: changeset)
      end
    end
  end
end

答案 1 :(得分:1)

执行use Waveia.Web, :controller

时导入的其他模块中存在这些函数(put_status/2render/3

你可以这样做:

def render_unprocessable_entity(conn, changeset) do
  conn
  |> Plug.Conn.put_status(:unprocessable_entity)
  |> Phoenix.Controller.render(ExampleApp.ChangesetView, "error.json", changeset: changeset)
end

你可以在一个模块中定义它,然后import controller web.ex函数中import MyModule, only: [render_unprocessable_entity: 2] 内的模块,但是应该注意的是,只要你将函数导入模块,隐藏模块定义的位置。这意味着在代码库上工作的其他人可能需要对代码进行一些挖掘以找到定义函数的位置。相反,我建议这样做:

render_unprocessable_entity/2

这样,查看控制器代码的人可以准确地看到@EnableAutoConfiguration(exclude = { ErrorMvcAutoConfiguration.class }) 函数的来源。