How to Find Current Abstract Route in Rails Middware

How to find current abstract route in Rails middware

You need to pass ActionDispatch::Request or Rack::Request to recognize method. Here is an example from another app:

main:0> req = Rack::Request.new("PATH_INFO" => "/customers/10", "REQUEST_METHOD" => "GET")
main:0> Rails.application.routes.router.recognize(req) { |route, params| puts params.inspect }; nil
{:controller=>"customers", :action=>"show", :id=>"10"}
=> nil

The same will work with ActionDispatch::Request. Inside middleware, you can easily create this object:

request = ActionDispatch::Request.new(env)

And if you need more information about recognized route, you can look into that route object that is yielded to block, by recognize method.

Update

The above solution will work for normal Rails routes, but since you only have spree engine mounted you need to use different class

request = ActionDispatch::Request.new(env)
Spree::Core::Engine.routes.router.recognize(request) { |route, params|
puts params.inspect
}

I guess the best would be find a generic solution that works with any combination of normal routes and engines, but this will work in your case.

Update #2

For more general solution you need to look at the source of Rails router, which you can find in ActionDispatch module. Look at Routing and Journey modules. What I found out is that the returned route from recognize method can be tested if this is a dispatcher or not.

request = ActionDispatch::Request.new(env)
Rails.application.routes.router.recognize(req) do |route, params|
if route.dispatcher?
# if this is a dispatcher, params should have everything you need
puts params
else
# you need to go deeper
# route.app.app will be Spree::Core::Engine
route.app.app.routes.router.recognize(request) do |route, params|
puts params.inspect
}
end
end

This approach will work in case of your app, but will not be general. For example, if you have sidekiq installed, route.app.app will be Sidekiq::Web so it needs to be handled in different way. Basically to have general solution you need to handle all possible mountable engines that Rails router supports.

I guess it is better to build something that will cover all your cases in current application. So the thing to remember is that when initial request is recognized, the value of route yielded to black can be a dispatcher or not. If it is, you have normal Rails route, if not you need to recursive check.

How can I find out the current route in Rails?

To find out URI:

current_uri = request.env['PATH_INFO']
# If you are browsing http://example.com/my/test/path,
# then above line will yield current_uri as "/my/test/path"

To find out the route i.e. controller, action and params:

path = ActionController::Routing::Routes.recognize_path "/your/path/here/"

# ...or newer Rails versions:
#
path = Rails.application.routes.recognize_path('/your/path/here')

controller = path[:controller]
action = path[:action]
# You will most certainly know that params are available in 'params' hash

How to get the current route in rails

To retrieve the URLs:

# Current URL:
request.original_url

# Current relative URL:
request.request_uri

Additionally, you can check with the current_page method whether you are in a certain route.

current_page?(my_path)
# => true / false

For Rails 4 use:

# Current URL:
request.original_url

# Current relative URL:
request.fullpath

Rails, how to get the route name from the actual request (routing reverse lookup)

IMHO you could use the code explained by KinOfCain on How can I find out the current route in Rails?

Rails.application.routes.router.recognize(request){ |route, matches, parameters| puts route.name }

The router is not storing the route recognized in any place at least I wasn't able to find it

How do I use a Rack middleware only for certain paths?

You could have MyMiddleware check the path and not pass control to the next piece of middle ware if it matches.

class MyMiddleware
def initialize app
@app = app
end
def call env
middlewary_stuff if env['PATH_INFO'] == '/foo'
@app.call env
end

def middlewary_stuff
#...
end
end

Or, you could use URLMap w/o the dslness. It would look something like this:

main_app = MainApp.new
Rack::URLMap.new '/'=>main_app, /^(foo|bar)/ => MyMiddleWare.new(main_app)

URLMap is actually pretty simple to grok.

match route using a splat. What does it do?

This is called route globbing and is explained in the Routing guide's section on route globbing:

Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example:

get 'photos/*other', to: 'photos#unknown'

This route would match photos/12 or /photos/long/path/to/12, setting params[:other] to "12" or "long/path/to/12". The fragments prefixed with a star are called "wildcard segments".

Wildcard segments can occur anywhere in a route. For example:

get 'books/*section/:title', to: 'books#show'

Rack middleware trapping stack trace

I finally found the solution to this. It turns out that the last line in what is considered my application is in the middleware. I was running the rest of the code in a local rails engine located in a components directory. All we needed to do was create a new silencer for BacktraceCleaner. Notice components dir is now included.

# config/initializers/backtrace_silencers.rb
Rails.backtrace_cleaner.remove_silencers!
Rails.backtrace_cleaner.add_silencer { |line| line !~ /^\/(app|config|lib|test|components)/}

If you are interested here is an issue I posted on the rails project about how to replicate this in detail. https://github.com/rails/rails/issues/22265

Rails Routes homepage setting throws Controller#index is missing a template for request formats

My View file is app/views/index.html.erb

This is the issue. Your view file should be present at app/views/foos/index.html.erb

Rails will automatically render a view that matches the name of the controller and action. Convention Over Configuration! Views are located in the app/views directory. So the index action will render app/views/foos/index.html.erb by default.

You can read more on this official Rails page.



Related Topics



Leave a reply



Submit