How to set session from templates or some different approaches?

I have a booking app. User directly pass to payment process after choosing slot. Before payment a user have to login or create account. My problem is I want to redirect to user after create account to continue payment process. I am using coherence library. Coherence library auto handle that for login action i need same thing for create action

In my mind i have 2 solution
1- If i can put session from view i want store payment url for redirect again
2- Creating a new controller “between payment and choosing slot”

I am new to programing is there better approaches for that ?

I’m not sure what you can do with coherence (perhaps customise it to redirect differently based on something) but I think the simplest way of doing it is using https://hexdocs.pm/plug/Plug.Conn.html#put_session/3
So when the user is going to pay and before you redirect them to the signup/login page you do something like:

put_session(conn, :on_payment, true) #or instead of true the url or something else you need to redirect them

And then after the signup/login, you just read the session again and see if :on_payment is there, get_session(conn, :on_payment) . If it is, use that to redirect and then clear that field by put_session(conn, :on_payment, nil) , so that on next login the user won’t be redirected again.

If you’re doing any of this outside a controller you need to prefix both with Plug.Conn. (so Plug.Conn.put_session and Plug.Conn.get_session).

1 Like

Thanks for reply. one problem is even in controller put_session(conn, :asd, "asd") doesnt work if it is not like conn = put_session(conn, :asd, "asda")

and my guess it should like that in view.@conn = Plug.Conn.put_session(@conn, :asd, "asd") or Plug.Conn.put_session(@conn, :asd, "asd")
but none of them work.

Currently in my view there are more than one slots. And every slot has different link. And these links are directly pass to user payment path with params.
<%= link "buy", to: payment_path(@conn, :new, date: @conn.params["date"], slot_id: slot.id), class: "btn btn-green" %>
If user is not loged in coherence doesnt allow user to execute payment controller. I mean there is no cart. So there is no controller determine slot id before payment process. That is why i want put_session in view. Do u think adding a middle controller before payment for store slot_id in session is better for my case ?

Well, usually you would lay it out as a pipeline, because as you are doing it you’re not passing the conn you changed unless you re-assing it with conn = ...

def create(conn, %{"session" => session_params}) do
    case AetherWars.Session.login(session_params, AetherWars.Repo) do
      {:ok, user} ->
        conn
        |> put_session(:current_user, user)
        |> put_session(:bearer, create_token(user.id))
        |> put_flash(:info, "Logged in")
        |> redirect(to: "/")
      {:error, message} ->
        conn
        |> put_flash(:info, message)
        |> render("new.html")
    end
  end

So the last redirect() or render() will receive that changed conn
If you do

put_session(conn, :something, something)
render conn, "something.html"

You’re saying render with this conn object that wasn’t changed.

If you do

put_session(conn, :something, something)
|> render "something.html"

You’re passing through the |> the previous element to the render function. It’s still render/2, but you omit the first parameter as it’s being passed through the pipe (|>)

On the last line of the “pipe” you could then pass the conn that you’ve mutated before, so that it can decide the redirect.

So perhaps something like (it’s just illustrative):

def login_function(.....) do
  conn
  |> put_session(:bearer, create_token(user.id))
  |> put_flash(:info, "Logged in")
  |> decide_redirect()
end

def decide_redirect(conn) do
  case get_session(conn, :on_payment) do
    nil -> redirect(conn, to: "/")
    url -> redirect(conn, to: url)
  end
end

Regarding transforming data on your view templates, don’t do it. The template (view layer) should only be concerned with presenting things. While the controller is concerned in transforming (or calling modules that transform) the data and then calling the appropriate template.

3 Likes

Thanks so much really informative post