aj-foster

aj-foster

Question

Given a route with a known controller action (:library_action) and a known helper name (as: :my_lib), how can I reliably generate the route’s path?

Background

I’m creating a library that integrates with Phoenix. This library provides a controller action MyLib.Controller.library_action/2, and asks consumers to add a route to their application’s router, such as:

get "/user/chosen/path/with/:param", MyLib.Controller, :library_action, as: :my_lib

For flexibility, I require the name of the action (:library_action) and the :as option, but leave the exact path up to the consumer. Furthermore, the consumer may choose to reimplement the :library_action controller action in their own application, ignoring the one provided by the library.

Whether the consumer uses the library-provided implementation or substitutes their own controller, it is necessary for other parts of the library to know the path for this action. In the past, the library could rely on the router’s Helpers module, and use the generated my_lib_path(conn :library_action, ...) function to create the path or URL. However, with Phoenix 1.7, the Helpers module is no longer guaranteed to be generated.

Other Notes

Here’s what we can do already:

  1. Get the current router dynamically from the conn via Phoenix.Controller.router_module/1.
  2. Get a list of known routes via Phoenix.Router.routes/1.
  3. Filter by the helper and plug_opts keys to find a route with the correct action name and :as option.
  4. Get the full path as a string, for example "/user/chosen/path/with/:param".
  5. Manually replace path segments with values, when necessary.

However, this process seems error-prone, especially the manual replacement of path segments.

All suggestions welcome! Thank you.

Showing Posts 1 to 10

dimitarvp

dimitarvp

That’s such an interesting question, shame nobody chimed in.

al2o3cr

al2o3cr

A more-explicit approach would be to ask users to configure your library with a {module, function, args} tuple that can generate the route.

For instance, you might configure {MyAppWeb.LibHelper, :my_lib_route, [:extra1, :extra2]} and define:

defmodule MyAppWeb.LibHelper do
  def my_lib_route(conn, params, _extra1, _extra2) do
    # extra1 and extra2 are just to show what happens
    MyAppWeb.my_lib_path(conn, :library_action, params)
  end
end

Your library could call this with:

def call_route({mod, fun, args}, conn, params) do
 apply(mod, fun, [conn, params] ++ args)
end
kip

kip

ex_cldr Core Team

Thanks for pinging this thread back into view. The possibility that helpers generation goes away also impacts localized route generation and localized helpers.

Both @BartOtten’s phoenix_localized_routes and my own ex_cldr_routes use helpers to generate routes at runtime to reflect the locale in effect at the time. This cannot be parsed at compile time because at that time the locale is not known.

Localized routes have the same helper name and same path structure but have path components translated (and may have locale components interpolated).

For that reason alone I hope that Helper generation can have a more definitive future.

aj-foster

aj-foster OP

I like this approach. There are a few places in the library where I plan to do this or something very similar. Especially if I can find a way to make the existing route helpers module meet the contract as well.

aj-foster

aj-foster OP

I certainly agree. Verified Routes is a powerful addition to Phoenix, and — just to be clear — I fully support it as the default for consumers. Maybe there is a different mechanism that would support 3rd-party libraries like the route helpers do now. Perhaps something with a bit less metaprogramming magic (since we wouldn’t be optimizing for the ergonomics of calling a helper function with exactly the right number of arguments). Not sure what that might look like, but the intersection of our use-cases is quite interesting.

BartOtten

BartOtten

@kip do you have time to talk about it with Phoenix Team? I am living without digital devices as much as possible and the network is really bad over here :slight_smile: Will be back in a week, but those 7 days might make a difference.

LostKobrakai

LostKobrakai

I wonder why you need the path helper in the first place. conn.script_name should give you the segments of the path, which was used to get to your controller. No need to consult the router or anything. Should work fine with both Plug.Router as well as Phoenix.Router. You can use that to build the path within the code you control. If the user wants to link to your controller they know the necessary details and can just use the normal phoenix tools (helpers, verified routes, …) to do so.

kip

kip

ex_cldr Core Team

It not really about knowing the path that got to the current controller. It’s generating paths and URLs to other parts of the site, where those paths are localised. Since they are localised the path cannot be validated at compile time (or at least I can’t think of a way). Using helpers give some minimal guarantee since an unknown function error at compile time acts as a signal.

LostKobrakai

LostKobrakai

I guess my question was more targeted at @aj-foster’s usecase, which seems to be related to urls to itself, rather than other pages.

aj-foster

aj-foster OP

Apologies for not being clear. In reality this library has multiple controller actions. I don’t need the path to the current controller action, but rather the path to another controller action also prescribed by the library. Hence the need to look up the action by name/helper.

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
widianto
I think I’ve found a small improvement I could contribute to <%= web_namespace %>.CoreComponents (installer/templates/phx_web/compo...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews