Expecting render function when using embed_templates in Live View 0.18.3

The error

Raised when navigating to http://localhost:4000/foo/bar

MainWeb.App.Root.render/2 is undefined or private

MainWeb.App.Root being the module passed to plug :put_root_layout in router.ex.

Not sure if this is a bug or I am missing something. Any help in figuring it out would be much appreciated.

Versions

  • Live View 0.18.3
  • Phoenix 1.6.15

The code

lib/main_web/router.ex

defmodule MainWeb.Router do
  use MainWeb, :router
  import Phoenix.LiveDashboard.Router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, {MainWeb.App.Root, :root}
    # other plugs...
  end

  scope "/foo" do
    pipe_through :browser
    live_session :foo do
      live "/bar", MainWeb.Foo.BarLive, :index
    end
  end
end

lib/main_web/app/root.ex

defmodule MainWeb.App.Root do
  use MainWeb, :html
  embed_templates "*"
end

lib/main_web/app/root.html.heex

<!DOCTYPE html>
<html lang="pt">
   <!-- other headers... -->
    <meta name="csrf-token" content={csrf_token_value()}>
    <.live_title suffix=" · Baz"><%= assigns[:page_title] %></.live_title>
    <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
    <script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
  <body>
    <%= @inner_content %>
  </body>
</html>

lib/main_web.ex

defmodule MainWeb do
  def html do
    quote do
      use Phoenix.HTML
      use Phoenix.Component
      alias MainWeb.Router.Helpers, as: Routes
      import Phoenix.HTML.Tag,
        only: [csrf_token_value: 0]
      import Phoenix.Controller,
        only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1]   end
  end

  def live_view(opts \\ []) do
    quote do
      use Phoenix.LiveView, unquote(opts)

      unquote(html())
    end
  end

  #defmacro __using__ , etc...
end

lib/main_web/foo/bar_live.ex

defmodule MainWeb.Foo.BarLive do
  use MainWeb, :live_view

  def render(assigns) do
    ~H"""
    <span>live!</span>
    """
  end
end

Main.App.Root, needs to be a view, meaning it has to use Phoenix.View which implements the missing render function.

Can you show us the code for that module?

Then code is in my original post, but here it goes:

And use MainWeb, :html uses Phoenix.Component.

The docs say Phoenix.View is to be replaced by Phoenix.Compoent, which does not require a render() implementation:
https://hexdocs.pm/phoenix_view/Phoenix.View.html#module-replaced-by-phoenix-component

So, this would be except for :put_root_layout? In that case I think either the docs need to be updated to clarify that, and/or the plug needs to be changed.

Your answer made pay more attention to the error stack trace. The call to render is coming from:

Phoenix.View.render_to_iodata (phoenix_view.ex:525)
Phoenix.Controller.render_and_send (controller.ex:772)
Phoenix.Router.__call__ (router.ex:354)

So it really looks like the template cannot be implemented as in Phoenix.Component — Phoenix LiveView v0.18.3. Which is what I was trying to do.

It sounds like you are on an older Phoenix. You need to be on Phoenix 1.6.15 for rendering function components from the controller stack. mix deps.update phoenix

errr, ignore me. We only support this on upcoming Phoenix 1.7 :slight_smile:

Oh, ok. Now it all makes sense Thanks!

Maybe it is worth mentioning this in Phoenix.View — phoenix_view v2.0.0.

Cheers!