How to allow multiple sets of templates

TL;DR : How can I have two different sets of templates in two different spots?

I have two sets of users, normal_users and developers. Under the myApp and myApp_web folders there will be folders for normal users & developers and inside each will be all the related stuff for each (models, controllers, …).

I have no idea how this works, and how Phoenix knows where to find the files still, but after moving the files everything still works, expect the templates.

But when I try to move the templates the app breaks. I’ve changed this in myApp_web.ex which fixes it for normal_users, but not for developers in lib/myApp_web/developers/templates.

use Phoenix.View,
        root: "lib/myApp_web/customer/templates",
        namespace: myApp

How can I get make two different locations possible for templates? Putting that root command twice causes an error.

What about bypassing this View func. Can’t I just tell the view which template to render directly? I can find any documentation explaining how.

defmodule MyApp.AdminSettingsView do
  use MyAppWeb, :view # WANT TO GET RID OF THIS 
end

I assume your using 1.6 here.

In your my_app_web.ex you have some functions/macros, which is what use MyAppWeb, :view hooks into (see the bottom of my_app_web.ex where it basically dispatches :view to view() and the elixir docs on use if you’re not familiar in what it does)

With this knowledge, we can define two “view functions”,


def user_view do
  quote do
    use Phoenix.View,
      root: "/some/path/users/templates"
    # ...
    # probably unquote(view_helpers) or something for shared stuff
  end
end

def dev_view do
  quote do
    use Phoenix.View,
      root: "/some/path/developers/templates"
    # ...
    # probably unquote(view_helpers) or something for shared stuff
  end
end

Then when we define the view, we can use the specialised functions

defmodule MyApp.Developer.SettingsView do
  use MyAppWeb, :dev_view
end

defmodule MyApp.Customer.SettingsView do
  use MyAppWeb, :user_view 
end

You probably also want to adjust the router two separate pipelines with different put_root_layout calls.

Not 100% that is everything you need to do but it should get you pretty close.

In 1.7 you do something similar,

def dev_live_view do
  quote do
    use Phoenix.LiveView,
      layout: {MyAppWeb.Developer.Layouts, :app}
    # ...
  end
end
defmodule MyAppWeb.Developer.Layouts do
  use MyAppWeb, :html
  embed_templates "layouts/*" # where this is lib/my_app_web/developer/layouts/* or whatever
end
defmodule MyAppWeb.Developer.SettingsLive do
  use MyAppWeb, :dev_live_view
end

As for

defmodule MyApp.AdminSettingsView do
  use MyAppWeb, :view # WANT TO GET RID OF THIS 
end

You could directly call

defmodule MyApp.AdminSettingsView do
  use Phoenix.View, root: ...
end

instead, but you’d also need to include all the other helpers too.

Possibly you can just do

defmodule MyApp.AdminSettingsView do
  use MyAppWeb, :view
  use Phoenix.View, root: ... # last call overwrites previous?
end

but honestly not sure if that works. It does for import but use has a bit more magic to it. Probably the most magic in all of elixir.

To answer the “everything but templates case” – elixir doesn’t care how modules are nested in folders at all. If a .ex file exists within lib/ it’s compiled. It it’s compiled it’ll be accessible.