I went to look at some code I wrote some months ago that fell into this category. To my own surprise, turns out I defined two modules in a single file to be able to colocate controller and template!
I understand controllers are a bit more complicated than LiveViews in this regard because they expose more flexibility, both in targeting different HTTP verbs and rendering different types of content from the same endpoint (HTML/JSON/etc).
Here’s a gist of the code I wrote, lib/myapp_web/controllers/temp_controller.ex
:
defmodule MyAppWeb.TempController do
use MyAppWeb, :controller
def show(conn, %{"id" => id} = _params) do
# ...
render(conn, :show, id: id)
end
end
defmodule MyAppWeb.TempHTML do
use MyAppWeb, :html
attr :id, :integer, required: true
def show(assigns) do
~H"""
{{ @id }}
"""
end
end
router.ex:
# ...
get "/temp", TempController, :show
In my understanding I wouldn’t want to change anything in the router side. I could have a single controller and choose which function to call based on HTTP verb:
get "/temp", TempController, :show
post "/temp", TempController, :save
On the controller, there’s a difference compared to mount/3
in that there are 2 arguments, conn
and params
– no session
. I think that’s okay.
When I call render
, IIRC the expectation is that there’s a module with a name similar to the controller TempController
→ TempHTML
, then I get to choose the template name which would typically be a file in disk. This part could be simplified, if I could write the template in the same module as the controller just like in LiveView.
Perhaps that could be done without changing Phoenix or LiveView, and instead updating the phx.new
generator to make use MyAppWeb, :controller
do some magic that “transforms a function returning HEEx in the controller module into a valid template”?
@zachdaniel does this resonate with your own needs?
I’ve also found a case where I deliberately made a static help page into a LiveView so that I can live navigate into and from it. If I would turn off the LiveSocket in this page, I would lose live navigation out of the page.
It also has the advantage that when I update the docs users immediately get to see the updated page without having to refresh.