Warning about no route when ~p in template refers to scope in router

Greetings,

I switched my hobby project to Phoenix 1.7
The new template uses ~p"/api/postcomic/"
This works, but compile gives the warning
warning: no route path for BecomicsWeb.Router matches "/api/postcomic/"
Is there a way to silence the warning?
The offending line is this:
<.form :let={f} for={c} action={~p"/api/postcomic/" <> Map.get(c, "id")}>
The router has:

  scope "/api", BecomicsWeb do
    pipe_through :api
    resources "/comic", ComicController, except: [:new, :edit]
    post "/postcomic/:id", ComicController, :post_from_form
  end

What you want to use is:

~p"/api/postcomic/#{c}"

That is, assuming c is a struct that implements Phoenix.Param, like an Ecto schema struct. Otherwise:

~p"/api/postcomic/#{c.id}"
2 Likes

What you are doing is concatenating the result of the ~p sigil to another string.
Router validation will only occur whatever is the result of the ~p sigil usage.

This is an example how your code looks like under the hood. So validation is only running in called function not on the result of concatenation

def p(route), do: route |> validate |> output

p("/api/postcomic/") <> Map.get(c, "id")
2 Likes

Thank you very much for your prompt answer.
c is a map, not a struct. And I did try c.id first, but that gives me:

key :id not found in: %{
  "__meta__" => #Ecto.Schema.Metadata<:loaded, "comics">,
  "id" => "1948708d-723e-445a-88e2-ccc8bec39384",
  "inserted_at" => ~N[2023-09-22 08:14:31],
  "name" => "Name",
  "updated_at" => ~N[2024-01-20 10:14:46],
  "url" => "",
  "url_for_href" => "https://example.com"
}

Thank you very much for your prompt answer.
Does this means that I should change the route so that api is no longer another scope? So that it would then look similar to

scope "/", BecomicsWeb do
    pipe_through :api
    resources "/api/comic", ComicController, except: [:new, :edit]
    post "/api/postcomic/:id", ComicController, :post_from_form
end

?
If I do that, will it not interfere with the already existing (in router.ex)

  scope "/", BecomicsWeb do
    pipe_through :browser
    get "/", PageController, :home
end

?

[deleted]

Just use proper interpolation and it should work

Yes, thank you. That worked.
I have not seen ~p[/path/somewhere] before.
Only ~p"/path/somewhere".

Will ~p[/path] always work or is it only under special circumstances?

Sigils can use multiple delimiters and you can choose one suiting your needs:

https://hexdocs.pm/elixir/syntax-reference.html#sigils

1 Like