Trouble making `live_path` work as intended

I started using live navigation for the first time when I ran into trouble.

I have defined a live_session like:

  scope "/", AppWeb do
    pipe_through :browser

    live_session :courses do
      live "/courses", Live.Courses, :index
      live "/courses/:id", Live.Course, :show
    end
  end

And I want to navigate between /courses and /courses/:id using push_redirect/2. And navigate between /courses/:id and /courses/:id?activity=SOMENUMBER using push_path/2. In both cases I intend use the live_path helper function, to get to target destination to navigate to.

This is where I don’t fully understand what to do. How does live_path work?

What arguments does it take? Does it take:
live_path(socket, live view module or action, params \\ [])

And how does Phoenix know whether a param is a param (e.g. id in /courses/:id) or a query string (e.g. activity in /courses/:id?activity=SOMENUMBER)?

I got the push_patch to work.

    socket = push_patch(socket, to: Routes.live_path(socket, __MODULE__, course_id, activity: activity_id))
    {:noreply, assign(socket, :activity, activity)}

However, the push_redirect does not work.

    socket = push_redirect(socket, to: Routes.live_path(socket, :show, id))
    {:noreply, socket}

Since your live routes definitions contain an action, you should not use live_path but snake_case_module_name_path. For instance:

live_course_path(@socket, :index)
live_course_path(@socket, :show, id)

or:

course_path(@socket, :index)
course_path(@socket, :show, id)

The uncertainty comes from the fact that you’re not following the convention of naming LV modules SomeNameLive, and I’ve never done that. You might have to rename your module to CourseLive for route helpers to work, I’m not sure. Give it a try. This part of the docs should provide some clarity: Phoenix.LiveView.Router — Phoenix LiveView v0.17.11

Thank you. I did read the docs about Phoenix.LiveView.Router. And I have tried renaming my modules and use the bla_bla_path(@socket, :action) syntax, but so far it still doesn’t work. And I haven’t found that many additional resources to read.

From some of the error messages I got a definition of live_path that I couldn’t find online:

live_path(conn_or_endpoint, PebbelWeb.Live.Pebbel, name, params \\ [])

Not sure what ‘name’ refers to here. And I have seen params being passed as values and as key-value pairs. Is it that Phoenix assumes you first pass the URL params and secondly any query string params?

You can run mix phx.routes and it will show you the names of the helper functions per route.

3 Likes

mix phx.routes indeed is very handy. I got everything to work now with the bla_bla_path() syntax.

This is working:

  alias PebbelWeb.Router.Helpers, as: Routes # I alias in the helpers into my module

  # I use this syntax (either the first or the second line) inside my handle_event callbacks.
  socket = push_redirect(socket, to: Routes.course_path(socket, :show, course_id)) 
  socket = push_patch(socket, to: Routes.course_path(socket, :show, course_id, activity: activity_id))

And as I’m writing this I think I finally understand why my live_path isn’t working. I thought live_path() and what I have been calling the bla_bla_path() were two categorically different syntaxes. I didn’t realize that I couldn’t use live_path() anymore, because I renamed my route live_path to course_path.

Despite this :sweat_smile:

I find if I don’t use the :as option with live_session routes, I don’t get the routes I expect. It’s a bit repetitive but gets the result I expect:

live_session :courses do
  live "/courses", Live.Courses, :index, as: courses
  live "/courses/:id", Live.Course, :show, as: courses
  live "/courses/:id/edit", Live.Course, :edit, as: courses
end

This will provide Routes.courses_path(socket, :index), Routes.courses_path(socket, :show, course), and Routes.courses_path(socket, :edit, course).

As far as I know you can’t pass :as to live_session like you can with scope but it’s been awhile… I remember fighting with it for a while to get what I wanted and the repeated :ases is what I ended up with it.

What should be “expected” is what is in the docs, and they’re pretty clear about this: Phoenix.LiveView.Router — Phoenix LiveView v0.17.11

:as - optionally configures the named helper. Defaults to :live when using a LiveView without actions or defaults to the LiveView name when using actions.

Maybe you meant “the routes I want” :wink:

Yep, I have RTF’d that M several times. I did indeed mean “the routes I want”.

1 Like