How to shorten a too long phoenix router path helper name?

Please suppose I have the following embedded routes in my router file :

`resources "/sections", SectionController do
  resources "/subsections", SubsectionController do
    resources "/categories", CategoryController do
      resources "/subcategories", SubcategoryController
    end
  end
end

With this i’m ending up with path helper like “section_subsection_category_subcatgory_path”.
I searched a way to specify a short name by providing options to the resources macro, but it doesn’t help…
The options I found are :param, :as, :name but none of them can change the path helper.

For the moment I define my self functions with shorter name in specific view file, to call the long name path helpers from my templates.

What could be a better solution to this ? Or maybe is it possible in elixir to define alias on function name ?

You could try putting this in your router file:

defdelegate short_name(), to: __MODULE__, as: :section_subsection_category_subcatgory_path
3 Likes

You can use scopes for nesting, while not affecting the path helper unless you want it to.

1 Like

Maybe I don’t understand what you’re suggesting… but if I avoid to use nested scopes here, it’s because with the resources macro I get the job done with a lot of less lines. If I use only nested scopes, for a CRUD set of routes, I will write at least 7 lines of code. That’s why I found “resources” macro very helpful for my use case.

Or maybe is there a way to do the same thing as “resources” macro does, with just scopes in few lines?

Hi, thank you for this tip. I didn’t know it. :slight_smile:
Thanks again. ^^

I answered a similar question on slack yesterday so here’s a copy of the example:

resources "/product", ProductController, only: [:index, :create, :update, :show] do 
  resources "/attribute", ProductAttributeValueController, only: [:show, :create]   
end
---
resources "/product", ProductController, only: [:index, :create, :update, :show]
scope "/product/:product_id" do
  resources "/attribute", ProductAttributeValueController, only: [:show, :create]
end

So it’s a line more for each level of nesting, but you can control the route helpers via the :as option on the scope.

5 Likes

Ah ok now it’s very clear for me. Just one more line at each nested level than what I’m doing and my problem of router helpers name is nicely solved. I could even change the name of the ID paremeter in the url if I want to (ex: /product/:prod_id).
Thank you ! :sunny:

I was looking for something like this today and stumbled upon this thread.
So, just in case someone else also encounters this, I want to leave a minor contribution…
As per today (using Phoenix 1.4.11), you can just:

resources "/blog", BlogController  do 
  resources "/posts", AwesomePostController, as: :post   
end
# Routes.blog_post_path(@conn, :index, @post)

As a remark on:

The documentation states that the :as option does exactly this (maybe it didn’t work in the past)

:as - configures the named helper exclusively

Well you’re right.
I was probably having trouble expressing myself, but I was looking for something a bit more complicated.

For example:

resources "/blog", BlogController  do
  resources "/posts", AwesomePostController, as: :post
  # Will result in Routes.blog_post_path(@conn, :index, @post)
 
  resources "/posts", AwesomePostController do
    resources "/comments", AwesomeCommentController, as: :comment, namespace: Blog
  end
  # Will result in Routes.blog_awesome_post_comment_path(@conn, :index, @post)
  # but I want Routes.blog_comment_path(@conn, :index, @post)
end

namespace option passed above is just my invention to explain the behaviour I was looking for.

So using scope is the better solution in my my case.

Now I’m wondering if one can still pass the :as option to resources macro when calling it with a do block:

resources "/blog", BlogController, as: :my_blog  do 
  resources "/posts", AwesomePostController, as: :post   
end
# Should result in Routes.my_blog_post_path(@conn, :index, @post)

or:

resources "/blog", BlogController, as: nil  do 
  resources "/posts", AwesomePostController, as: :post   
end
# Should result in Routes.post_path(@conn, :index, @post)

Probably the last case won’t work.

Edit: So to sum up, the as option allow to alter the default Router helper name at the nesting level of the route definition, but it can’t alter the parent namespace. I hope what I’m saying is understandable. :sweat_smile:

1 Like

I understand your original problem now. This namespace example you provided is in fact what scopes represent conceptually in my head :grin:.

When I was looking for a solution I’ve searched exactly this: “short path helper phoenix”, and this thread was the first result on Google’s search. So I hope my comment ads value for anyone else reaching for a similar solution - worst-case scenario two useful techniques are being explained in this thread haha :laughing:

1 Like

Hello from the future!

  resources "/requests", GroupRequestController, only: [], as: :requests do
      post "/accept", GroupRequestController, :accept, as: :accept
      post "/decline", GroupRequestController, :decline, as: :decline
    end

creates:
request_accept_path and request_decline_path instead of group_request_group_request_paths

Cheers to the 2024 folks.

1 Like

Afaik you can even ‘reset’ the nesting of the helper names. It’s in the docs (writing at mobile, so no link). Something should have the value :false.

2 Likes

For reference, it’s in the Phoenix.Router.scope/2 Options doc:

  • :as - a string or atom containing the named helper scope. When set to false, it resets the nested helper scopes.
  • :alias - an alias (atom) containing the controller scope. When set to false, it resets all nested aliases.
2 Likes