Hi everyone, I’m making a shortener and the idea is that after somebody POST their url, it redirects them to “api/shorturl/new/” from “/” and then they receive the content of the %Short structure.
To hold the values inside %Short I’m trying to assign a map to conn.assigns but it doesn’t seem to work.
My controller:
defmodule ShortenerWeb.UrlController do
use ShortenerWeb, :controller
alias Shortener.Api
alias Shortener.Urls.Short
def index(conn, _) do
if conn.assigns == %{} do
conn |> json(%{error: "Wrong Format"})
else
conn |> json(conn.assigns[:short])
end
end
def show(conn, id) do
id
end
def create(conn, %{"short" => %{"original_url" => original_url}}) do
{:ok, short} = Api.short(original_url)
conn = assign(conn, :short, Map.from_struct(short))
redirect(conn, to: Routes.url_path(conn, :index))
end
end
The shortener structure
defmodule Shortener.Urls.Short do
use Ecto.Schema
import Ecto.Changeset
schema "urls" do
field :original_url, :string
end
def changeset(short, attrs \\ %{}) do
short
|> cast(attrs, [:original_url])
|> validate_required([:original_url])
end
end
Here’s part of my Router just in case:
defmodule ShortenerWeb.Router do
use ShortenerWeb, :router
...
scope "/api/shorturl/new", ShortenerWeb do
pipe_through :api
get "/", UrlController, :index
post "/", UrlController, :create
get "/:id", UrlController, :show
end
scope "/", ShortenerWeb do
pipe_through :browser
get "/", PageController, :index
end
end
It looks like you are assigning things to conn in the create action and then expecting them to exist in the index action? This is not how connections work. Basically each conn resembles one request. When the user’s browser makes a new request (after being redirected to index's URL), a new connection structure is created and the old assigns no longer exist.
Thank you @Nicd, I made it work with sessions, here’s my code if anyone is interested:
defmodule ShortenerWeb.UrlController do
use ShortenerWeb, :controller
alias Shortener.Api
alias Shortener.Urls.Short
def index(conn, _) do
conn = fetch_session(conn)
map = get_session(conn, :short)
if is_number(map.id) do
conn |> json(%{
original_url: map.original_url,
short_url: map.id
})
else
conn |> json(%{error: "Wrong Format"})
end
end
def show(conn, id) do
id
end
def create(conn, %{"short" => %{"original_url" => original_url}}) do
{:ok, short} = Api.short(original_url)
conn = fetch_session(conn)
conn = put_session(conn, :short, Map.from_struct(short))
redirect(conn, to: Routes.url_path(conn, :index))
end
end