Liveview redirect root "/" to specific page

I want to redirect the Phoenix router to a specific page so “/” renders the first navigation item.

Currently I do this using a root page:

# router.ex
defmodule AppWeb.Router do
   ...
  scope "/", AppWeb do
    pipe_through :browser



    live_session :navigation, on_mount: [AppWeb.Navigation] do
      live "/", RootLive.Index
      live "/comics", ComicLive.Index
      live "/comics/new", ComicLive.New, :new
      live "/comics/:id", ComicLive.Show, :edit
      ...

In RootLive.index this happens:

defmodule StripeljeeWeb.RootLive.Index do
  use StripeljeeWeb, :live_view

  def handle_params(_unsigned_params, _uri, socket) do
    {:noreply, socket |> redirect(to: "/comics")}
  end

  def render(assigns) do
    ~H"""
    ...
    """
  end
end

This does work, but Dializer complains about this:

Type mismatch for @callback mount/3 in Phoenix.LiveView behaviour.

Expected type:

  {:ok,
   %Phoenix.LiveView.Socket{
     :assigns => Phoenix.LiveView.Socket.assigns_not_in_socket() | map(),
     :endpoint => atom(),
     :fingerprints => {nil | binary(), map()},
     :host_uri =>
       :not_mounted_at_router
       | %URI{
           :authority => URI.authority(),
           :fragment => nil | binary(),
           :host => nil | binary(),
           :path => nil | binary(),
           :port => nil | char(),
           :query => nil | binary(),
           :scheme => nil | binary(),
           :userinfo => nil | binary()
         },
     :id => binary(),
     :parent_pid => nil | pid(),
     :private => map(),
     :redirected => nil | tuple(),
     :root_pid => pid(),
     :router => atom(),
     :transport_pid => nil | pid(),
     :view => atom()
   }}
  | {:ok,
     %Phoenix.LiveView.Socket{
       :assigns => Phoenix.LiveView.Socket.assigns_not_in_socket() | map(),
       :endpoint => atom(),
       :fingerprints => {nil | binary(), map()},
       :host_uri =>
         :not_mounted_at_router
         | %URI{
             :authority => URI.authority(),
             :fragment => nil | binary(),
             :host => nil | binary(),
             :path => nil | binary(),
             :port => nil | char(),
             :query => nil | binary(),
             :scheme => nil | binary(),
             :userinfo => nil | binary()
           },
       :id => binary(),
       :parent_pid => nil | pid(),
       :private => map(),
       :redirected => nil | tuple(),
       :root_pid => pid(),
       :router => atom(),
       :transport_pid => nil | pid(),
       :view => atom()
     }, Keyword.t()}


Actual type:

  {:noreply,
   %Phoenix.LiveView.Socket{
     :redirected => {:redirect, map()} | {:live, :patch | :redirect, map()},
     _ => _
   }}

The mount/3 callback should return data in format {:ok, socket} not how you would do when handling an event: {:noreply, socket}.

Sorry, but how does this relate? I try to understand but can’t.

When defining a mount callback like this:

  def mount(_params, _session, socket) do
    {:ok, socket}
  end

The warning from dialyzer is not much different:

Type mismatch for @callback mount/3 in Phoenix.LiveView behaviour.

Expected type:

  {:ok,
   %Phoenix.LiveView.Socket{
     :assigns => Phoenix.LiveView.Socket.assigns_not_in_socket() | map(),
     :endpoint => atom(),
     :fingerprints => {nil | binary(), map()},
     :host_uri =>
       :not_mounted_at_router
       | %URI{
           :authority => URI.authority(),
           :fragment => nil | binary(),
           :host => nil | binary(),
           :path => nil | binary(),
           :port => nil | char(),
           :query => nil | binary(),
           :scheme => nil | binary(),
           :userinfo => nil | binary()
         },
     :id => binary(),
     :parent_pid => nil | pid(),
     :private => map(),
     :redirected => nil | tuple(),
     :root_pid => pid(),
     :router => atom(),
     :transport_pid => nil | pid(),
     :view => atom()
   }}
  | {:ok,
     %Phoenix.LiveView.Socket{
       :assigns => Phoenix.LiveView.Socket.assigns_not_in_socket() | map(),
       :endpoint => atom(),
       :fingerprints => {nil | binary(), map()},
       :host_uri =>
         :not_mounted_at_router
         | %URI{
             :authority => URI.authority(),
             :fragment => nil | binary(),
             :host => nil | binary(),
             :path => nil | binary(),
             :port => nil | char(),
             :query => nil | binary(),
             :scheme => nil | binary(),
             :userinfo => nil | binary()
           },
       :id => binary(),
       :parent_pid => nil | pid(),
       :private => map(),
       :redirected => nil | tuple(),
       :root_pid => pid(),
       :router => atom(),
       :transport_pid => nil | pid(),
       :view => atom()
     }, Keyword.t()}


Actual type:

  {:noreply,
   %Phoenix.LiveView.Socket{
     :redirected => {:redirect, map()} | {:live, :patch | :redirect, map()},
     _ => _
   }}


If you have changed the code and the warning still persists, try to delete the _build folder and start the server again, sometimes there are cache bugs.

This line looks wrong. Unless there is a default identifier you can use that I don’t about, it should either look like: on_mount: [{AppWeb.Navigation, :some_identifier}] or just on_mount: {AppWeb.Navigation, :some_identifier} if you only have one callback.

@D4no0 this makes no difference. Restarting the Elixir language server also solves nothing. Running mix phx.server does not show this error, only ElixirLS shows the warning.

If you have changed the code and the warning still persists, try to delete the _build folder and start the server again, sometimes there are cache bugs.

@sodapopcan I looked into this through the documentation and I indeed use the :default identifier.

1 Like

The error still lists the actual type as {:noreply, …}, where {:ok, …} is expected. So that’s what you should be looking out for.

You should have started with the fact that the problem comes from ElixirLS, the build folder for elixir-ls for vscode is located in .elixir_ls. What I do in such cases is close code editor, remove _build, .elixir_ls and then it should compile everything from a clear start.

I’ve been also noticing having a lot of times this happen lately, maybe a bug introduced in some update, hopefully it will be fixed soon.

1 Like

Thank you for pointing out that elixir_ls has its own .elixir_ls folder. Deleting this solved its complaints.

1 Like