Samuei2000

Samuei2000

How to redirect a logged in user's route to another

The question is

If a logged in user visits the / route, make them redirect to the /guess route.

I have

scope "/", PentoWeb do
    pipe_through :browser

    get "/", PageController, :home
  end

and

scope "/", PentoWeb do
    pipe_through [:browser, :require_authenticated_user]

    live_session :require_authenticated_user,
      root_layout: {PentoWeb.Layouts, :root},
      on_mount: [{PentoWeb.UserAuth, :ensure_authenticated}] do
      live "/users/settings", UserSettingsLive, :edit
      live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
      live "/guess", WrongLive
    end
  end

Because the user must be logged in before redirect “/” to “/guess”, I delete the get "/", PageController, :home line , and add a new line get "/", WrongLive in live_session , to make route “/” inside the same live_session . But it shows

(CompileError) lib/pento_web/router.ex:75: undefined function get/2 (there is no such import)
    (phoenix_live_view 0.19.3) expanding macro: Phoenix.LiveView.Router.live_session/3
    lib/pento_web/router.ex:69: PentoWeb.Router (module)
    (phoenix 1.7.6) expanding macro: Phoenix.Router.scope/3
    lib/pento_web/router.ex:66: PentoWeb.Router (module)

What is the best way to do it?

Most Liked

Samuei2000

Samuei2000

Can you explain what is a live view’s controller? I haven’t seen it in books.

If I don’t modify this part:

scope "/", PentoWeb do
    pipe_through :browser

    get "/", PageController, :home
  end

,then it means every request to route “/” will be processed by PageController’s “home” action. So PageController is the only controller that I can modify to implement the questions’s redirection. Then I write these codes in page_controller.ex:

defmodule PentoWeb.PageController do
  use PentoWeb, :controller

  def home(conn, _params) do
    if conn.assigns[:current_user] do
      redirect(conn, to: ~p"/guess")
    else
      render(conn, :home, layout: false)
    end
  end
end

I think it’s the answer. And I find that, after redirection, the user has in the same @session_id

I think there are some related and similar concepts:

  1. conn.assigns[:current_user] in plugs/controllers, to get the current_user of a conn.

  2. plug :fetch_current_user in router.ex “pipeline :browser do”, which adds a key in a conn’s assigns called current_user if the user is logged in

  3. socket.assigns.current_user in user_auth.ex on_mount function, which performs authentication for mounting live views inside a live_session.

arcanemachine

arcanemachine

Notice that the / route isn’t a live view. That means you can’t put it in a live_session block.

Since you’re changing a single view, the easiest way would be to change that view’s behavior in its controller (I see that you’re doing the LiveView book but this is a dead-view problem).

  • One way that Phoenix checks if the requesting user is authenticated is to check if conn.assigns[:current_user] is truthy (you can do this in the controller).

  • The method used to redirect a dead-view is called redirect. Here’s a link to the relevant docs page: Controllers — Phoenix v1.8.8

Hopefully that’s enough to get you going.

arcanemachine

arcanemachine

Yeah, that’s how I would do it for a single route.

If there were multiple routes with the same requirement (redirect user to /guess) and you didn’t want to modify each controller, you could do something like this instead:

Modify the scope in the router:

lib/pento_web/router.ex

  scope "/", PentoWeb do
   pipe_through [:browser, :redirect_authenticated_user_to_guess_live]  # this line has changed

    get "/", PageController, :home

    # example route, here for demonstration purposes only:
    # get "/some-other-route", SomeOtherRouteController, :some_route
  end

(The page won’t render until we define the redirect_authenticated_user_to_guess_live/2 function that we referenced in the previous example. Let’s do that now.)

lib/pento_web/user_auth.ex

  def redirect_authenticated_user_to_guess_live(conn, _opts) do
    if conn.assigns[:current_user] do
      redirect(conn, to: "/guess") # redirect the user
    else
      conn # continue the plug pipeline
    end
  end

The page should do the same thing as your original answer without requiring any work in the controller. The logic will apply to any route in that scope.


I’ll try and explain why this works, but I’m also learning, so I’ll probably get this wrong: The reason we can use an atom to reference the function is because:

  1. We already imported PentoWeb.UserAuth in the router, so the function is available in the module namespace. (That’s also why the :require_authenticated_user function works. It’s from the same module.)

  2. There’s a function somewhere in the router that calls functions based on their names when passed as atoms. I’m not totally sure why, but that’s how it works. On some level, the function names must be exposed as atoms when they are imported.


The router is interesting because it’s one of the first things a new Phoenix developer will see, and yet it is full of some pretty complex functionality. I have faith that there’s a very good reason for how everything is laid out, but my God was it confusing to figure out what was going on there.

It really makes me appreciate the simplicity of Django’s urls.py. But then, Phoenix seems to expose the complexity to you directly, instead of hiding it away like other frameworks, which seems to give you more flexibility in the long run. So the tradeoffs are worth it IMO.

Where Next?

Popular in Questions Top

siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
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
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43487 311
New
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
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52673 488
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 127089 1222
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement