Dudo
Dudo

Reputation: 4169

How to find rails route pattern from url

Given a rack request where I know the path, e.g. /things/1, how can I get the route reference e.g. /things/:id?

I can use Rails.application.routes.recognize_path to get the controller and action, but I’m explicitly looking for an obfuscated path.

Is there anyway to get the recognized route given a controller#action, maybe?

Upvotes: 3

Views: 762

Answers (2)

Alex
Alex

Reputation: 29719

Rails v7.1

They've made it a bit easier:

request.route_uri_pattern
#=> "/users/:id/edit(.:format)"

https://api.rubyonrails.org/v7.1.3.2/classes/ActionDispatch/Request.html#method-i-route_uri_pattern


Rails v7.0

The only place I knew where that information is available is bin/rails routes. It's using inspector to collect all the information:

https://github.com/rails/rails/blob/v7.0.4.3/actionpack/lib/action_dispatch/routing/inspector.rb

Maybe there is something else you'll find there. But I extracted the main bit that you're asking for:

# in a controller or a template

<% request.routes.router.recognize(request) do |route, _params| %>
  <%= route.path.spec.to_s %> # => /users/:id(.:format)
<% end %>
# in a console

>> Rails.application.routes.router.recognize(
  ActionDispatch::Request.new(Rack::MockRequest.env_for("/users/1/edit", method: :get))
) {}.map {|_,_,route| route.path.spec.to_s }
=> ["/users/:id/edit(.:format)"]

route here is ActionDispatch::Journey::Route instance which has all the information about a route.


I don't have even a remote clue what this does, but it does it:

>> Rails.application.routes.routes.simulator.memos("/users/1/edit").first.ast.to_s
=> "/users/:id/edit(.:format)"

# NOTE: if route doesn't match it will `yield` and raise
# no block given (yield) (LocalJumpError)
# just rescue or give it an empty block.

https://github.com/rails/rails/blob/v7.0.4.3/actionpack/lib/action_dispatch/journey/gtg/simulator.rb#L25

Upvotes: 7

sbounmy
sbounmy

Reputation: 33

Following up the answer from Alex: on Rails 7.1, I had the error:

undefined method 'path' for nil:NilClass

What worked for me:

Rails.application.routes.router.recognize(
      ActionDispatch::Request.new(Rack::MockRequest.env_for("/users/1/edit", method: :get))
    ) {}.map { |route| route.path.spec.to_s }

Upvotes: 1

Related Questions