Gulliver

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

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

APB9785

APB9785

Creator of ECSx

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.

Where Next?

Popular in Questions Top

New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New

Other popular topics Top

malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42920 311
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36128 110
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New

We're in Beta

About us Mission Statement