Gulliver
Directory structure for templates in Phoenix app
How can I change the default directory structure for templates in Phoenix app?
I just tried to create a new project and added some authentication to it by doing the “mix phx.gen.auth Accounts User users”. The result worked as expected but the directory/file structure it generated was quite a mess in my opinion. All the generated templates were directly under the “templates” directory, as user_registration, user_session and so on.
So I wanted to fix this by creating a “user” subdirectory and moving all the user related templates there but I couldn’t find a place where to tell phoenix where these templates files are. The generated view files were quite empty and they all just seem to call this “view” function. So where can I tell which templates this view actually renders and where they are?
Marked As Solved
tadasajon
I just refactored a project I’m working on to address precisely this issue. I added a new function to myapp_web.ex, so now I have both view and accounts_view:
def view do
quote do
use Phoenix.View,
root: "lib/quizdrill_web/templates",
namespace: QuizdrillWeb
# Import convenience functions from controllers
import Phoenix.Controller,
only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1]
# Include shared imports and aliases for views
unquote(view_helpers())
end
end
def accounts_view do
quote do
use Phoenix.View,
root: "lib/quizdrill_web/accounts/templates",
namespace: QuizdrillWeb
# Import convenience functions from controllers
import Phoenix.Controller,
only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1]
# Include shared imports and aliases for views
unquote(view_helpers())
end
end
Then, I created a new accounts/ folder at lib/myapp_web/accounts/ and I created three directories inside it: controllers/, views/, templates/. So my directory structure inside myapp_web looks like this:
myapp_web/
├── accounts/
│ ├── controllers/
│ │ ├── user_auth.ex
│ │ ├── user_confirmation_controller.ex
│ │ ├── user_registration_controller.ex
│ │ ├── user_reset_password_controller.ex
│ │ ├── user_session_controller.ex
│ │ └── user_settings_controller.ex
│ ├── templates/
│ │ ├── user_confirmation/
│ │ ├── user_registration/
│ │ ├── user_reset_password/
│ │ ├── user_session/
│ │ └── user_settings/
│ └── views/
│ ├── user_confirmation_view.ex
│ ├── user_registration_view.ex
│ ├── user_reset_password_view.ex
│ ├── user_session_view.ex
│ └── user_settings_view.ex
├── controllers/
│ └── page_controller.ex
├── templates/
│ ├── dashboard/
│ │ └── index.html.heex
│ ├── layout/
│ │ ├── live.html.heex
│ │ ├── _user_menu.html.heex
│ │ ├── root.html.heex
│ │ ├── admin.html.heex
│ │ └── app.html.heex
│ └── page/
│ ├── index.html.heex
│ └── dashboard.html.heex
├── views/
│ ├── error_helpers.ex
│ ├── error_view.ex
│ ├── layout_view.ex
│ ├── page_view.ex
│ └── dashboard_view.ex
├── endpoint.ex
├── gettext.ex
├── telemetry.ex
└── router.ex
The controllers and the views can be moved into the new directories without affecting anything, but if the templates are moved then they will be in the wrong location – so I have edited each of the view files so it is an :accounts_view rather than a :view, following the adjustment I made to lib/myapp_web.ex. For example:
defmodule QuizdrillWeb.UserConfirmationView do
use QuizdrillWeb, :accounts_view
end
Now I have everything having to do with user accounts under the accounts/ directory and out of the way.
I’d appreciate any feedback, incidentally – the one thing I don’t like about this approach is the code-duplication between the view and accounts_view functions in lib/myapp_web.ex – I’d prefer to only change the root directory for the templates rather than copy-paste the whole function in the way that I did.
Also Liked
stefanchrobot
Take a look at the options taken by use Phoenix.View.
See here: Liveview conventions, Why put liveview template in live folder? - #7 by stefanchrobot
APB9785
The view function is in lib/my_app_web.ex:
def view do
quote do
use Phoenix.View,
root: "lib/my_app_web/templates",
namespace: MyAppWeb
# Import convenience functions from controllers
import Phoenix.Controller,
only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1]
# Include shared imports and aliases for views
unquote(view_helpers())
end
end
You can define other alternatives to view here and use them instead when needed.








