Phoenix - 控制器和视图之间的回调操作

问题描述

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

这就是我所做的

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...