Extending a Phoenix Application

Hi there!

Trying to determine what’s the right approach to extending a Phoenix app’s functionality.

I have a small hex package, Fuentes, for handling double-entry accounting. I’m looking to build another package, Phoenix_Fuentes, to allow people to integrate that functionality into their application. My intention was to have a PhoenixFuentes.AccountController as well as default views allowing people to just add resources "/accounts", PhoenixFuentes.AccountController to their router.ex and all would be right in the world.

I thought I’d be able to do something like:

defmodule PhoenixFuentes.AccountController do
  use (SomeFunctionToGetParentApp).Web, :controller

  def index(conn, _params) do
    render conn, "index.html"
  end
end

But was shown in the #phoenix channel on slack how that might result in circular dependencies at compile time and just wasn’t a good idea.

Looking into the use macro, I see it calls (as generated):

      use Phoenix.Controller<%= if namespaced? do %>, namespace: <%= application_module %><% end %>
<%= if ecto do %>
      alias <%= application_module %>.Repo
      import Ecto
      import Ecto.Query
<% end %>
      import <%= application_module %>.Router.Helpers
      import <%= application_module %>.Gettext

so I can’t just duplicate it’s functionality as the library won’t know what application (the application_module) it is a dep of.

Accordingly, right now I’m seeing two options:

  1. A mix generator to copy templates of the account controller and account views to the parent app, to allow people to use TheirApp.AccountController instead of PhoenixFuentes.AccountController.
  2. A standalone phoenix application which is under an umbrella application.

I was intending to provide Option 1 to allow people the ability to customize controllers and views as needed, but was hoping there was a way to facilitate “trying it out” without needing to touch their own codebase. I’m also not sure if Option 2 is even a true option?

Has anyone encountered other Elixir libraries that try to accomplish this type of “extension” functionality?
Any other options or better ways of solving this problem that I should consider?

Thanks!

2 Likes

It’s not clear why you need to do something like this within your library? What would the above achieve in the context of your controller? Instead, if you left it as use Phoenix.Controller, what prevents that from working for you? You can serve the templates from your app as normal and it would just work. If the user wanted to override the templates, they could use put_view MyApp.MyFuentesView in a pipeline that calls your router/controller? If you can give a better description on the kind of extension you’re going for, I can say more, but the injection approach from the “parent” app is not the right way to think about it :slight_smile:

4 Likes