ErrorView which is used to handle errors doesn’t provide conn or stuff like that. Is there a way to attach layout anyway? Showing 404 error without any layout in current project is no-go.
The only way i see at this moment is to copy all the markup from app.html.eex which is less than ideal solution.
defmodule AppWeb.ErrorView do
use AppWeb, :view
def render("404.html", assigns) do
render("404.html", assigns)
end
...
P.S. Anything else, like redirect on 404/error is not possible as well
Thank you. That’s what i was looking for. Hard to find
For history, solution looks like this:
defmodule AppWeb.ErrorView do
use AppWeb, :view
def render("404.html", assigns) do
Phoenix.View.render_layout AppWeb.LayoutView, "app.html", assigns do
render("not_found.html", assigns)
end
end
...
Thanks for positing the solution @thousandsofthem - it really helped me in arriving at my own version of solving this problem. This is what I went with:
defmodule AppWeb.ErrorView do
use AppWeb, :view
def template_not_found(template, assigns) do
render(
"error.html",
Map.put(assigns, :message, Phoenix.Controller.status_message_from_template(template))
)
end
end
And a very stripped down version of my error/error.html.heex looks something like this:
I found this approach helpful because it allows me to create a “generic” error page that:
Doesn’t rely on any other layouts (minimize risk of an error during the rendering of an error page).
Can still share things like styling between the error pages.
Allows for small customizations, like the message, via assigns.
I know it’s a different approach than the one you went for, and I think both approaches have merit. I just wanted to share this approach since it might be helpful for someone :).
I set root_layout and layout to true and here’s what i got:
Server: localhost:4000 (http)
Request: GET /wrong/pathname
** (exit) an exception was raised:
** (RuntimeError) cannot use put_layout/2 or put_root_layout/2 with atom/binary when layout is false, use a tuple instead
(phoenix 1.6.7) lib/phoenix/controller.ex:513: anonymous fn/3 in Phoenix.Controller.do_put_layout/3
(elixir 1.13.4) lib/map.ex:830: Map.update!/3
(phoenix 1.6.7) lib/phoenix/endpoint/render_errors.ex:106: Phoenix.Endpoint.RenderErrors.render/6
(phoenix 1.6.7) lib/phoenix/endpoint/render_errors.ex:78: Phoenix.Endpoint.RenderErrors.instrument_render_and_send/5
(phoenix 1.6.7) lib/phoenix/endpoint/render_errors.ex:64: Phoenix.Endpoint.RenderErrors.__catch__/5
{DemoWeb.LayoutView, :error} corresponds to lib/demo_web/templates/layout/error.html.heex.
{DemoWeb.LayoutView, :skip} corresponds to an almost empty template (lib/demo_web/templates/layout/skip.html.heex):
<%= @inner_content %>
You may find that I’m using {DemoWeb.LayoutView, :error}(this is a customized root layout for error pages) instead of the default root layout {DemoWeb.LayoutView, :root}. The reason is from here:
It is worth noting that we did not render our 404.html.heex template through our application layout, even though we want our error page to have the look and feel of the rest of our site. This is to avoid circular errors. For example, what happens if our application failed due to an error in the layout? Attempting to render the layout again will just trigger another error. So ideally we want to minimize the amount of dependencies and logic in our error templates, sharing only what is necessary.