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

Tee
can someone please explain to me how Enum.reduce works with maps
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
sabri
Can someone explain the settings of pool_size of Ecto in config file? and what is the recommend size? Thanks
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
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
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New

We're in Beta

About us Mission Statement