VerifiedRoutes & building dynamic urls through interpolation

Hello all,

Long time lurker, I have what is a hopefully “small” problem for the great minds of this community.

We have a parent organisation with users (admins) and multiple child entities, each with their associated users and resources.

Users of the children entities browse resources via a set of urls and associated views e.g

/users
/posts
/users/$username/posts

*(I am using made up urls for simplicity)

and for the parent org, we provide access to the same resources via urls prefixed with /publishers/$entity_id/ + /.../ e.g

/publishers/$entity_id/users
/publishers/$entity_id/posts
/publishers/$entity_id/users/$username/posts

So far so good.

We initially did something like this in our .heex templates, it is “clean enough”, it works

<.link :if={@is_admin} href={~p"/publishers/#{@entity}/users"} class="..">Users</.link>
<.link :if={not(@is_admin)} href={~p"/users"} class="..">Users</.link>

However, we are finding that this duplication everywhere isn’t very satisfying. :confused:

Another approach:

<.link href={@is_admin && ~p"/publishers/#{@entity}/users" || ~p"/users"} class="..">Users</.link>

This is also fine but gets unwieldy when my urls get relatively long.

Yet another approach (conditionally prefixing publishers/#{@entity} to the route ~p"/users/#{@user}/posts"

<.link href={~p"/#{@is_admin && "publishers/#{@entity}/users/$username" || "/users/$username"}/posts"} class="..">Users</.link>

gives compile warnings saying 'no route path for Webapp.Router for "..."' which is a perfectly valid warning.

And we can’t concatenate url ~p"/publishers/#{@entity}" + ~p"/users/#{@user}/posts".

My question:

Is there an obvious right way to do this that we are missing? Or have you been faced with something similar since the release of VerifiedRoutes and how did you handle it?

Thanks in advance! :smiley:

Components could work:

def posts_link(%{user: %User{is_admin: true}} = assigns) do
  ~H|<.link href={~p"/publishers/#{@entity}/users"} class="..">Users</.link>|
end

def posts_link(assigns) do
  ~H|<.link href={~p"/users"} class="..">Users</.link>|
end

You could also do one component and case the different routes.

Really this is point of verified routes, though. It lets you write explicit readable routes that actually look like paths and if they ever change you’ll get told exactly what you need to change. But extracting works too!

1 Like

Would it work to move the path generation to a function?

def users_path(entity, %User{is_admin: true}), do: ~p"/publishers/#{@entity}/users"
def users_path(entity, %User{is_admin: false}), do: ~p"/users"
1 Like

You are both right @sodapopcan @nTraum, this is potentially an approach I could live with.

Calling a <.resource_link/> component in my .heex files for each resource type scratches that unclean itch I’ve been struggling with.

The constant duplication everywhere there is a link on a page in approach 1, is gone and the poor readability in the other approaches is abstracted away somewhere I don’t have to see it regularly. :sweat_smile:

Thanks for the replies @sodapopcan + @nTraum

1 Like

Next week I try to release a major improved version of Routex. But you can already see if the features of that lib make sense for your use case: GitHub - BartOtten/routex at bo/unofficial-0.3.0-1

Drop me a message when you want to try. Then I will publish a new alpha at Hex and a new sample app; which makes reading the docs and sample usage code a lot easier.

1 Like

Just an update: The main branch has been updated so one can visit the main branch at GitHub - BartOtten/routex