问题描述
我正在为我们的系统构建一个管理工具应用程序。 我想记录每个用户的每一个动作。
这就是我所做的
defmodule AdminToolWeb.UserController do
use AdminToolWeb,:controller
...
def delete(conn,%{"id" => id}) do
current_user = Guardian.Plug.current_resource(conn)
with %User{} <- user = Accounts.get_user(id) do
Accounts.delete_user(user)
conn
|> put_flash(:info,"#{user.id} deleted.")
|> Activities.log(current_user)
|> redirect(to: Routes.user_path(conn,:index))
end
end
...
end
问题是我必须在我的应用程序中的每个控制器的每个操作中使用管道 |> Activity.log(current_user)
。
有没有办法实现这样的东西?
Controller -> (activitylogPlugOfSorts) -> View
使用自定义插件并像这样调用它?
defmodule AdminToolWeb.UserController do
use AdminToolWeb,:controller
import AdminToolWeb.Plugs.Activities
plug :log
...
但是应该在控制器和视图之间调用。
我希望有更好的方法。
解决方法
您在此处寻找的是 controller plugs,它确实可以直接插入到控制器级别。它们将在控制器操作之前运行,因此当插件运行时您将没有机会知道尝试的操作是否会成功。但是,您可以使用控制器插件到 setup a callback,它将在控制器操作之后(但在发送响应之前)运行。一个例子可能是:
defmodule HelloWeb.Plugs.ActionLogger do
import Plug.Conn
require Logger
def init(default),do: default
def call(conn,_default) do
register_before_send(conn,fn conn ->
if (response_code_2xx?(conn) do
Logger.info("action taken: #{extract_action(conn)}")
end
conn
end)
end
end
其中 response_code_2xx?/1
和 extract_action/1
留给读者作为练习。