Using dynamic nested urls with verified paths doesn't work

I’m trying to push_patch to a dynamic route (where the current liveview is located).
In my library’s liveview helpers, I call it in handle_event as

socket |> push_patch(to: ~p"/#{current_path}?#{options}")

(options is a map which need to be encoded by ~p)

Where current_path is being fetched in handle_params using

current_path = URI.parse(url).path |> String.trim_leading("/")

There are 2 problems with this.

  1. ~p turns any nested url containing / into %2Fs which mess up the url.
  2. Compiler throws a warning warning: no route path for DemoWeb.Router matches "/#{current_path}?#{options}", although the current liveview’s path (/products or /posts) is defined in the router.

Using |> push_patch(to: "/#{current_path}?#{Plug.Conn.Query.encode(options)}") does seem to work (although compiler still throws a warning), but I don’t want to go back to this as these methods are deprecated after verified routes.

What’s the best way to do this?

Lastly, is there a better way to fetch the url of current LiveView?
@chrismccord and @josevalim

~p is about verifying at compile time that a route would be routeable by the application/router. For #{current_path} there’s nothing which could be verified in the first place. You can just remove the sigil. Nothing forces you to use it.

I need the options map to be encoded into the URL. Is this possible without the ~p?

https://hexdocs.pm/elixir/URI.html
https://hexdocs.pm/plug/1.17.0/Plug.Conn.Query.html

2 Likes

There are also unverified_* functions in VerifiedRoutes which may or may not be of interest.

However, if I may offer some more general advice: it may be better to generate your paths based on the actual state of your application rather than the current path. Like, if you are on a page for a post = %Post{} then perhaps you should regenerate the URL as ~p"/posts/#{assigns.post}?#{params}, like you would wherever you link to that page.

So using something like this is ok?

 push_patch(socket, to: "/#{current_path}?#{Plug.Conn.Query.encode(options)}")

Removing ~p didn’t get rid of the compiler warning

Is there a more elegant way to get the url of the current liveview?

Check out routex, it could give you some ideas or maybe you could even use it. :call_me_hand:

1 Like

If you try Routex, use main branch of Git or the release candidates of version 1.2 as it has been greatly improved lately (incl fixes by @ken-kost). Routex (using the Plugs and LiveViewHooks extensions) also assigns @url for you to be accessible in templates.

2 Likes