AlchemistCamp
How to replace render_existing/3 with function_exported?/3
I have several apps with something like the following in the app.html.eex or app.html.heex:
<%= render_existing(view_module(@conn), "_meta." <> view_template(@conn), assigns)
|| render AppWeb.LayoutView, "_meta.html", assigns %>
This setup renders the metadata for a given view “foo.html” by looking for “_meta.foo.html” and rendering it if it exists. I use the meta templates for holding SEO-related meta, OG meta, and various other tags that go into the tag of a document.
If meta doesn’t exist, then the logic above renders a default template called layout/_meta.html. as the default source.
After upgrading Phoenix, I’m now seeing a compilation warning telling me to use function_exported?/3 instead of render_existing/3.
warning: Phoenix.View.render_existing/3 is deprecated. Use function_exported?/3 instead
lib/app_web/templates/layout/app.html.eex:2: AppWeb.LayoutView."app.html"/1
What would be a good way of following this advice (without breaking the behavior of 100+ _meta templates)? There’s a considerable gap in the interface of the suggested replacement function.
Most Liked
AlchemistCamp
I gave it my best shot this morning during a livestream before work and unfortunately, just couldn’t get a working solution.
Without render_existing/3, we can no longer determine whether a template exists. Depending on deployment strategies, the filesystem is sometimes no longer available.
Unfortunately, function_exported?/3 doesn’t fill the gap since render/3 will always be exported.
This means the only options would be
- writing and maintaining hundreds and hundreds of meta functions throughout the application
- crawling the filesystem at compile time to create a list of all existing template names
- using try and rescue on every page load
- some kind of macro wizardry I haven’t yet been able to think of
LostKobrakai
The idea is moving to function components over templates. Function components are a lot more flexible than templates and given they’re based on (differently named) functions there’s less phoenix magic needed – magic the phoenix teams seems to like to get away from. But not everybody will jump on board of restructing their projects immediately, therefore I feel the deprecation was a bit premature.
You’d replace your code with something like this:
<%= if function_exported?(view_module(@conn), :meta 1), do: view_module(@conn).meta(Map.merge(assigns, %{template: view_template(@conn)}), else: meta(assigns) %>
# LayoutView
def meta(assigns) do
~H"""
…
"""
end
# OtherView
def meta(%{template: "index.html"} = assigns) do
~H"""
…
"""
end
…
From those meta functions you can also call your existing templates using:
render("_meta.#{assigns.template}", assigns)
AlchemistCamp
I looked at the docs before creating this thread. It’s because the examples provided weren’t applicable to my use case that I asked here in the first place.
I’ve found that _meta.foo.html files for simpler cases and defining a render("_meta.foo.html", assigns) functions in the view for more complex cases a very useful pattern.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









