Setting dynamic layouts in LiveViews that correspond with the hostname

Okay…

router.ex

...

  # put host and configuration data into session for retrieval from liveview
  defp sessionify_configuration(conn, _opts) do
    import Plug.Conn

    case MyApp.Sites.Domain.get_by_name(conn.host) do
      {:ok, domain} ->
        configuration =
          domain.site_id
          |> MyApp.Sites.Site.get_by_id!()
          |> MyApp.Sites.load!(:configuration)
          |> Map.get(:configuration)

        conn
        |> put_session(:configuration, configuration)
        |> put_session(:current_host, conn.host)
        |> put_session(:current_path, conn.request_path)

      {:error, error} ->
        IO.inspect(error)
        raise "No Domain found with the name " <> conn.host
        conn
    end
  end

  pipeline :do_config do
    plug :sessionify_configuration
  end

  scope "/", MyAppWeb do
    pipe_through [:browser, :do_config]

    # login not required
    ash_authentication_live_session :authenticated_optional,
      on_mount: [
        {MyAppWeb.LiveUserAuth, :live_user_optional},
        {MyAppWeb.AssignConfiguration, :assign_configuration}
      ] do

      live "/", PublicLive.Index, :index
    end

...

assign_configuration.ex

def on_mount(:assign_configuration, _params, session, socket) do
  socket =
    socket
    |> Phoenix.Component.assign(:configuration, Map.get(session, "configuration"))
    |> Phoenix.Component.assign(:current_host, Map.get(session, "current_host"))
    |> Phoenix.Component.assign(:current_path, Map.get(session, "current_path"))

  {:cont, socket}
end

index.ex

  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign(:page_title, "public")
      |> assign(:testificate, "testificatey")

    layout = {MyAppWeb.Layouts, socket.assigns.configuration.theme}

    {:ok, socket, layout: layout}
  end

This is the flow I have right now that’s working! I was able to remove extraneous hooks and consolidate some functionality into the on_mount. And it looks like Phoenix actually is letting me pass the layout template as a string, too, although it does complain that this is deprecated. So no String.to_atom for now (and if I do have to do that later I think I can just whitelist it based on existing themes).

So the only thing I have to append to every liveview is

layout = {MyAppWeb.Layouts, socket.assigns.configuration.theme}
{:ok, socket, layout: layout}

Not too bad.

And to be clear I meant like they could potentially manipulate the session based on the hostname. If you are whitelisting hostnames then it’s no problem.

This area is all public stuff you can view by simply going to that site, so that should be fine as I understand it. Unless there’s anything drastic I’m missing.