How to do load a custom template, or otherwise "@inner_content" in Phoenix?

In an layout I have this standard line:

    <%= @inner_content %>

For some controllers and actions I want to be able to render a custom template instead of the default one, if a custom template exists. For instance, if template/article/custom.index.html.eex exists for the route /articles/, the layout should load the custom.index.html.eex instead. Otherwise, load the default one - index.html.eex

Note that in each Controller and each action the Elixir code should remain unchanged, preferably:

render(conn, "<index, edit, show, etc...>.html")

Namely, I want to program that on the level of the layout.

How to do it?

I figure it’d be similar to

   <%= render_existing(@view_module, "footer." <> @view_template, assigns) %>

but for the main content

1 Like

In the view module you can do:

render("index.html", assigns) do
  try do
    render_template("custom.index.html", assigns)
  rescue
    FunctionClauseError -> render_template("index.html", assigns)
  end
end

Exceptions in general hurt performance. Wouldn’t your solution also?

I need that not only for index, but for any template as long as its name starts with “custom.”

This is afaik the simplest way to do that without relying on undocumented/private api of phoenix.

Ok, but I’m asking - would it hurt performance?

It’s not the most performant for sure, but the question is rather would it matter. That’s you need to test with your expected load. Other solutions would require phoenix to build in such a fallback mechanism, as all the macro logic doesn’t really allow you to inject your own code between handling of different cases.

Previously, before <%= @inner_content %>, I could’ve used somthing like this:

   <% a1 = render_existing(@view_module, "custom." <> @view_template, assigns) do %>
   <% if a1 do %>
    <%= a1 %>
   <% else %>
     <%= render(@view_module, @view_template, assigns) do %>
   <% end %>

right?