I am trying to remove the "catch all" or "default" route from a production rails application. I'm interested in maintaining operation while gathering a log of it's usage so that I can replace it with the appropriate hard coded routes.
So, given I have the following default route line in my config/routes.rb file.
match '/:controller(/:action(/:id))'
How could I create or retrieve a log of every time that route gets hit. This log would ideally include only requests actually handled by this route along with parameters and would need to leave the route itself functioning as normal.
Another possibility would be to make use of Rails router constraints option:
match '/:controller(/:action(/:id))', constraints: -> (req) {
Rails.logger.info("Default route used: #{req.path.inspect}")
true
}
Note: the lambda returns true so that the match succeeds.
One way you can do this is the change the default route to:
match ':controller(/:action(/:id))(.:format)', :using_default_route => true
Then put the following function into app/controllers/application_controller.rb
before_filter do
if params[:using_default_route]
logger.info("Default route for #{request.path.inspect}. params = #{params.inspect}")
end
end
Related
So in our Rails 4.2 application, there is the alchemy_cms gem which requires its routes to be mounted last in config/routes.rb.
SampleApp::Application.routes.draw do
#other routes for the rails app here
# :
# :
mount Alchemy::Engine => '/'
end
We get routes like "/somehacker/routingurl" which then falls out to the Alchemy::Engine to handle, resulting in a default 500 error. If I wanted to do a custom 404 error, then the proper way to do it is to build a custom 404 page and have Alchemy handle the redirect? Otherwise since the Alchemy docs specify that it has to be the last route in config/routes.rb, there won't be a way to add a catchall route to redirect to some kind of error page I assume.
EDIT:
One of the problems is that there are some routes that are like the invalid "somehacker" route above that do need to be parsed by the Alchemy routing engine, such as "/en/us" where "en" is a valid locale. This is why I initially thought to put the route handling in the Alchemy engine's routes file.
If it is difficult for you to configure and use the Alchemy cms gem to redirect unknown routes into a custom defined page, you can use the bellow method to implement the same with a small coding tweak given bellow:
Rails 4.XXX
1. First Method.
(routes.rb)
You can still use a simple get to redirect all unknown routes.
get '*path', to: 'home#index'
If you wish to provide routing to both POST and GET requests you can still use match, but Rails wants you to specify the request method via via.
match "*path" => "home#index", via: [:get, :post]
Remember that routes.rb is executed sequentially (matching the first route that fits the supplied path structure), so put wildcard catching at the bottom of your matchings.
Here you can replace the home#index with any custom path that you defined in you application, also note that it is important to keep this redirection code only at the bottom of routes.rb.
2. You can follow the bellow tutorial on the same problem in a different perspective to solve can be found.
Custom 404 error page with Rails 4
I'm creating an engine that needs to insert some routes into the application's router. For this particular gem, I'd rather not application's routes.rb if possible. Is there a way to insert routes at a particular location in the router via code? I'm looking for an API that does something like:
Rails.application.routes.insert("resources :foos", :before => "some string in routes.rb")
If I create a config/routes.rb inside the engine and define some routes, this kind of works. Rails is smart enough to mix the engine's routes into the application's routes, but it tacks them on at the end of the route list. I need them to appear at the beginning so the engine's routes take priority.
I'm aware that I can namespace the routes by mounting the engine in the application's routes.rb, but this creates a routing structure that I don't really want. I want the engine's routes to look they are a part of the application by defining some routes in the actual application.
I have a workaround which is to add the following to the application's routes.rb.
Rails.application.routes.draw do
MyEngine.setup_routes(self)
#...other routes below
end
MyEngine.setup_routes looks like
def self.setup_routes(map)
map.get 'a_path', :to => 'a_controller#a_path'
end
This at least allows me to control the point where the routes get defined in the application's route list, but the user still has to manually update his routes.rb (or I have to build an installer that does it). It seems like there should be a way to tell rails to tack some routes onto the start of the route list...
I am using Angular html5mode so have Rails routing set to redirect all failed requests to root
# Angular catch all to allow page refresh
get '*page' => "home#index"
This works just fine, except when an Angular module requests a missing template (/assets/templates/page.html for example), when it causes an endless loop
How can I tell Rails to catch all routes, except things in /assets ?
I noticed this is quite old, but found it through Google and wasn't happy with the only answer here. Since I worked through this myself I will share my solutions.
Use the format parameter in your route
get "/*path" => "home#index", format: false
Simply disable the format option for the wildcard path so it ignores requests with any format (e.g. css, js, png...)
Use a constraint in the route
get "/*path" => "home#index", constraints: -> (req) { !(req.fullpath =~ /^\/assets\/.*/) }
Specify a constraint option with a simple lambda checking your path value, not the best regular expression but shows the idea I'm going for here...
Personally I use the format parameter in my apps, the constraints option also lets you pass in an object, check out the rails guide for more info -> http://guides.rubyonrails.org/routing.html#advanced-constraints
The routes are evaluated top to bottom, so you can do the following:
# Catch all missing templates
get '/assets/templates/*page' => '/assets/templates/default.html'
# Angular catch all to allow page refresh
get '*page' => "home#index"
Missing templates will be caught by the first statement and all other missing routes will be caught by the second statement
I implemented a simple custom errors solution.
this one: http://ramblinglabs.com/blog/2012/01/rails-3-1-adding-custom-404-and-500-error-pages
everyhing is working fine except the missing routes in the routes.rb file..
in order to get to my error_controller when there is a missing route i did the wildcard solution: match '*not_found', to: 'errors#error_404'
but... now when i try to enter a sub section of my site which seats under:
/admin, i get to the error page. the wilcard gets triggered, even tough the route for admin section is defined in a different route file, under: config/routes/admin.rb
what can I do?
thanks
edit:
using rails 3.0.20 and ruby 1.8.7
If you're using Rails 3.2+, there is a simpler solution for your routes. First in 'config/application.rb' set your app as the error handler
config.exceptions_app = self.routes
Now when there is an your app will look to your routes to handle it. In 'config/routes.rb' you can add a route such as:
match "/404", :to => "errors#not_found"
A more verbose explanation can be found here.
OK so until I will update to Rails 3.2+
I simply put '*not_found', to: 'errors#error_404' into the last route file that is loaded.
that way its truly in the end of the routes and now all my routes work. and the error is still fired when needed.
I'm tired of creating a new line in my routes.rb every time I add a new method in my controller. Is there a way in routes.rb to tell rails to accept any defined action in a given controller? I'm pretty sure I've done this before but can't remember how. I still need to explicitly specify the controller, however, because many other people use this routes file.
Thanks!
This is from the default generated config/routes.rb file
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id(.:format)))'