Mark Karavan
Mark Karavan

Reputation: 2674

Adding controller methods in ex_admin (Phoenix)

I am working with the ex_admin package for Phoenix. After doing a successful standard install, I create a User resource with a name and an avatar (which will reference a file on S3)

>> mix phoenix.gen.model User users name:string avatar:string

>> mix admin.gen.resource User

modules: [
    MyApp.ExAdmin.Dashboard,
    MyApp.ExAdmin.User
]

>> iex -S mix phoenix.server

Works great. Now I'd like to add modify the equivalent of the create function that would exist in web/controllers/user_controller.ex if I had made the resource with mix phoenix.gen.html User .... However, despite the fact that the backend is CRUD'ing properly, I can't find any controllers for this specific resource.

What is the best way to tackle this? Create a web/controllers/user_controller.ex file and have it override? Add the function as a module elsewhere?

Upvotes: 1

Views: 369

Answers (1)

Steve Pallen
Steve Pallen

Reputation: 4507

There two ways you can hook into controller actions in ExAdmin.

1. Add either a before_filter or an after_filter on the controller.

For this approach, use the controller macro in your resource file.

defmodule MyApp.ExAdmin.License do
  use ExAdmin.Register
  register_resource MyApp.License do
    # ...
    controller do
      before_filter :set_current_user, only: [:create, :update]
      before_filter :set_updated_by, only: [:update]

      def set_current_user(conn, params) do
        new_params = put_in(params, [:license, :user_id], MyApp.Authentication.current_user(conn).id)
        {conn, new_params}
      end
      def set_updated_by({conn, params}, _params) do
        new_params = put_in(params, [:license, :updated_by_id], MyApp.Authentication.current_user(conn).id)
        {conn, new_params}
      end
    end
  end
end

Checkout the docs from master here

2. Create you own controller

With this approach, you create a controller with the actions you want to override. To use your custom controller, you will need to add routes for the desired actions. Just make sure the routes you create are above this block in your router.

scope "/admin", ExAdmin do
  pipe_through :browser
  admin_routes
end

Here is an example of a custom controller. Note that you need to include the @resource "my_resource".

defmodule ExAdmin.ClientController do
  @resource "clients"
  use ExAdmin.Web, :resource_controller
  alias UcxRemote.{Client, Repo, ClientService}
  require Logger
  use Utils

  def create(conn, _defn, %{_format: "json", client: client_params} = _params) do
    result = do_create conn, client_params
    case result do
      {:ok, client} ->
        put_view(conn, UcxRemote.ApiClientView)
        |> render("create.json", client: client)
      {:error, _changeset} ->
        json conn, %{errors: ["Validation failed"]}
    end
  end

  def create(conn, defn, params) do
    result = do_create conn, params[:client]
    case result do
      {:ok, client} ->
        conn
        |> put_flash(:notice, "Client was successfully created.")
        |> redirect(to: admin_resource_path(client, :show))
      {:error, changeset} ->
        errors = get_errors(changeset, "creating")
        conn
        |> put_flash(:error, errors)
        |> handle_changeset_error(defn, changeset, params)
    end
  end

  defp do_create(conn, %{user_id: user_id} = client_params) do
    changeset = %Client{user_id: user_id}
    |> Repo.preload([user: :company])
    |> Client.changeset(client_params)
    Repo.insert(changeset)
  end
end

Here is the route:

 scope "/", ExAdmin do
    pipe_through :browser
    post "/clients", ClientController, :create
 end

Upvotes: 1

Related Questions