我有一个共享控制器功能,我想在控制器之间重复使用:
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中吗?但也许我不应该让那个文件太大?
干扰代码的最佳方法是什么?
答案 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
你可以这样做:
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 })
函数的来源。