1

我正在为我们的系统构建一个管理工具应用程序。我想记录每个用户所做的每一个动作。

这就是我所做的

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

...

但它应该在控制器和视图之间调用。

或者我应该在 View 模块中放置一个函数?

我希望有更好的方法。

4

1 回答 1

1

您在这里寻找的是控制器插头,它确实可以直接插入控制器级别。它们将在控制器操作之前运行,因此您将没有机会在插件运行时知道尝试的操作是否会成功。但是,您可以使用控制器插件设置将控制器操作之后(但在发送响应之前)运行的回调。一个例子可能是:

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?/1extract_action/1留给读者作为练习。

于 2021-01-25T14:52:05.303 回答