Domain-oriented web folder structure

I’m trying to find a way to organize my web folder into high-level application areas, and I’m starting with an admin area. However, the way I understand it, Phoenix encourages the following web folder structure:

hello_web
├── controllers
│   ├── foo_controller.ex
│   ├── bar_controller.ex
├── templates
│   ├── foo
│   │   ├── index.html.eex
│   │   ├── ...
│   ├── bar
│   │   ├── index.html.eex
│   │   ├── ...
├── views
│   ├── foo_view.ex
│   ├── bar_view.ex

while I’m trying to organize my folder structure like so:

hello_web
├── foo
│   ├── foo_controller.ex
│   ├── foo_view.ex
│   ├── templates
│   │   ├── index.html.eex
│   │   ├── ...
├── bar
│   ├── bar_controller.ex
│   ├── bar_view.ex
│   ├── templates
│   │   ├── index.html.eex
│   │   ├── ...

It seems a bit odd that on one hand Phoenix encourages domain-oriented organization of code into contexts (each with its own folder structure) in the main application folder, while on the other hand it encourages framework-oriented organization in the web folder.

What I tried so far is enforce the above folder organization, which seems OK up to the point when I try to override the template folder location per view. I don’t see a way to do this. The only option I found was in hello_web.ex, with the root: option to Phoenix.View:

use Phoenix.View, root: "lib/hello_web/templates"

but that seems to just change the root template folder for all views, and cannot be set on a view-by-view basis.

8 Likes

I’m doing the same thing. You can set it on a view-by-view basis. Just modify the view function in your hello_web.ex file so it starts like this:

  def view(opts \\ [root: "lib/hello_web/templates"]) do
    opts = opts ++ [namespace: HelloWeb]

    quote do
      use Phoenix.View, unquote(opts)

At the bottom of the file add a second macro to the one that is already there:

  defmacro __using__({which, opts}) when is_atom(which) do
    apply(__MODULE__, which, [opts])
  end

Now start every view where you want to override the template location with code like this:

defmodule HelloWeb.UserView do
  use HelloWeb, {:view, [root: "lib/hello_web/user/templates", path: ""]}

That should do the trick!

10 Likes

20 posts were split to a new topic: Discussion about domain-orientated folder structures in Phoenix

I’ve written some phoenix generators (vphx for “vertical phoenix”) that generate a new app_web.ex file which supports this architecture and generates HTML that respects this folder organization. If people are interested I can release them somewhere. I still haven’t converted the phx.gen.auth generator into the new architecture (this generator is much more complex and generates many more files).

4 Likes

Do it! Many Django converts will thank you…

Ok, I’ll publish them after porting the auth generators. I’ve also ported my Mandarin package (a set of generators to generate an admin interface) into “vertical slices” (this version is not yet released).

The big problem with these packages that generate code is how to test them - I’m currently doing manual integration tests only because setting up the infrastructure to generate and test these seems quite complex