SophieDeBenedetto

SophieDeBenedetto

Author of Programming Phoenix LiveView

Forwarding requests to LiveView

I’m developing a Hex package that provides a set of LiveView routes mounted from the router via live '/path', LiveViewName, session: [:blah]. This package is then meant to be included in another Phoenix app. That app’s router can then forward requests to the Hex package’s paths, including the live mounted paths.

The hex package’s router looks like this:

defmodule RailwayUiWeb.Router do
  use RailwayUiWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug Phoenix.LiveView.Flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  scope "/", RailwayUiWeb do
    pipe_through :browser

    get "/", PageController, :index
    live "/published_messages", PublishedMessageLive.Index, session: [:current_user_uuid]
    live "/consumed_messages", ConsumedMessageLive.Index, session: [:current_user_uuid]
  end
end

And the calling application’s router forwards requests like this:

  scope path: "/admin", as: :admin do
    forward("/railway-ipc", RailwayUiWeb.Router, namespace: "admin/railway-ipc")
  end

Route forwarding is working in that the pages provided by the package do render when a user visits /admin/raiwlay-ipc/published_messages, for example. But the live view then crashes with the message:

 (ArgumentError) cannot invoke handle_params nor live_redirect/live_link to \"http://localhost:4000/admin/railway-ipc/published_messages\" because it isn't defined in RailwayUiWeb.Router\n    (phoenix_live_view) lib/phoenix_live_view/utils.ex:135

When running the hex package as a standalone phoenix app, the live views render and run just fine.

Is there some reason why using forward to forward to paths that are mounted in the destination router via live '/path' wouldn’t work?

Most Liked

josevalim

josevalim

Creator of Elixir

Hi @SophieDeBenedetto!

Unfortunately LiveView cannot be mounted on a separate router which is then forwarded to. The reason is that LiveView does route lookups and we currently don’t store the “forwarding path”.

There is an OK-ish solution to this problem which is to encapsulate the routes in a macro:

defmodule AdminRoutes do
  defmacro __using__(opts) do
    quote do
      scope unquote(opts) do
        live ...
      end
  end
end

And then in the router you can do:

use AdminRoutes, path: "/admin"

Another issue with mounting a LiveView in an external application is that you also need to define a socket in the endpoint. We were discussing some options to make the whole process easier but we haven’t reached a conclusion yet.

SophieDeBenedetto

SophieDeBenedetto

Author of Programming Phoenix LiveView

Thanks for the response! Yep after digging into the source code I can see the problem. I’ll lay it out below from anyone else who might find this helpful:

  • phoenix_live_view.js implements the bindNav function which sends an event to LiveView’s channel with the URL from window.location.href. At this point, that href is the forward mounted route, in my case containing the path /admin/railway-ipc/published_messages
  • The channel handles this event by calling PhoenixLive.Utils.live_link_info!/3 with that URL.
  • This in turn calls Phoenix.Router.route_info/4 where the router argument is the router to which we are forwarding, in my case the router that mounts the LiveView (RailwayUiWeb.Router), and the path argument is the path from the URI, /admin/railway-ipc/published_messages. Since that router implements a route for just /published_messages, not /admin/railway-ipc/published_messages, this raises the error I reported above.

I will definitely play around with your suggestion and see where it gets me. Thanks again!

FeeJai

FeeJai

I think I just ran into the same problem. So I found the super ugly solution to just hack the path_info in the conn:

  pipeline :routerscope do
    plug :rescoper
  end

  scope "/subapp", Subapp do
    pipe_through [:browser, :routerscope]
    forward "/", Router
  end

  def rescoper(conn, [] = _opts) do
    %{conn | path_info: [Enum.at(conn.path_info, 0)] ++ conn.path_info}
  end

This works. How can it be done in a nicer way?

Where Next?

Popular in Questions Top

vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New

Other popular topics Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

We're in Beta

About us Mission Statement