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
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:
-
conn.assigns[:current_user] in plugs/controllers, to get the current_user of a conn.
-
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
-
socket.assigns.current_user in user_auth.ex on_mount function, which performs authentication for mounting live views inside a live_session.
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
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:
-
We already imported
PentoWeb.UserAuthin the router, so the function is available in the module namespace. (That’s also why the:require_authenticated_userfunction works. It’s from the same module.) -
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.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









