Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
569 views
in Technique[技术] by (71.8m points)

elixir - Phoenix - Callback action between controller and view

I am building an admin tool app for our system. I want to record every action made by every user.

Here's what I did

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

The problem is I have to pipe |> Activity.log(current_user) in every action of every controller I have in my app.

Is there a way to implement something like this? Controller -> (ActivityLogPlugOfSorts) -> View using a custom plug and call it like this?

defmodule AdminToolWeb.UserController do
  use AdminToolWeb, :controller
  import AdminToolWeb.Plugs.Activities

  plug :log

...

but It should be called between controller and view.

Or should I put a function inside a View module instead?

I hope there is a better way.

question from:https://stackoverflow.com/questions/65884754/phoenix-callback-action-between-controller-and-view

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

What you're looking for here are controller plugs which can indeed be inserted directly at the controller level. They will run before the controller action, so you will not have the opportunity when the plug runs to know if the attempted action will be successful. However you can use the controller plug to setup a callback that will be run after the controller action (but before the response is sent). An example might be:

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

where response_code_2xx?/1 and extract_action/1 are left as exercises for the reader.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...