In my rails app I have defined the routes so users can access records like http://mydomain.com/qwe2
But if they type a wrong "qwe2" they get a 500 page. I think a 404 would be more appropriate.
How can I change the error page that is shown? Thanks
Create a catch-all route at the bottom of config/routes.rb:
map.connect '*path', :controller => 'unknown_route'
Then in app/controllers/unknown_route_controller you can do:
class UnknownRouteController < ApplicationController
def index
render :file => "#{Rails.root}/public/404.html", :layout => false,
:status => 404
end
end
This will render your 404 page for any unknown routes.
The only reason you get a 500 code is if your application throws an exception. This could be due to a missing route, where you do not have anything defined that matches that, or because your controller or view has crashed out.
In a production environment you might want to catch all errors generated by your application and present a better error screen, if appropriate, or a 'Not Found' page if required.
For example, a brute-force catch-all exception catcher might be defined as:
class ApplicationController < ActionController::Base
if (Rails.env.production?)
rescue_from Object, :with => :uncaught_exception_rescue
end
protected
def uncaught_exception_rescue(exception)
render(:partial => 'errors/not_found', :status => :not_found)
end
end
Returning a 404-type error is easy if you can tell when you want to do it:
render(:partial => 'errors/not_found', :status => :not_found)
Make sure you have some kind of default route or you will get these errors all the time. Usually this is done by adding a catch-all route at the very end of your routes.rb:
map.default '/*path', :controller => 'default', :action => 'show'
Then you can do whatever you want with this request.
Related
I'm working to build a Rails 5 app, not in API mode, but for an API.
One of my APIs is broken. When I load the url in the browser: http://localhost:4300/api/v1/skills.json
The browser is returning just:
500 Internal Server Error
If you are the administrator of this website, then please read this web application's log file and/or the web server's log file to find out what went wrong.
Given I'm in development mode, how can I get Rails to output more helpful information like in previous versions of Rails?
Add to application.rb the following line:
config.exceptions_app = self.routes
so you can render custom errors adding in routes:
Rails.application.routes.draw do
get "/404" => "errors#not_found"
get "/500" => "errors#exception"
post "/500" => "errors#exception"
get "/400" => "errors#exception"
post "/400" => "errors#exception"
for example I display:
class ErrorsController < ApplicationController
def not_found
render :json => {:error => "not-found"}.to_json, :status => 404
end
def exception
render json: {
error: {
message: env["action_dispatch.exception"].to_s,
detail: env["action_dispatch.exception"]
}
},
:status => 500
end
end
I'm implementing dynamic error pages into an app, and have a feeling it's looking in the public folder for (now non-existent) templates, rather than following the routes I've set up.
In config/application.rb I've added the line config.exceptions_app = self.routes to account for this.
I've then added the following to my routes:
get "/not-found", :to => "errors#not_found"
get "/unacceptable", :to => "errors#unacceptable"
get "/internal-error", :to => "errors#internal_error"
And the errors controller looks like so:
class ErrorsController < ApplicationController
layout 'errors'
def not_found
render :status => 404
end
def unacceptable
render :status => 422
end
def internal_error
render :status => 500
end
end
Going to /not-found shows the template as it should be, though visiting any non-existing URL (i.e. /i-dont-exist) renders an empty page.
The only reason I could see for this would be that the exception handling needs the routes to be, for example, get "/404", :to => "errors#not_found", though, ironically, it's not finding the route for /404 (and no, that's not just it working :) ).
Any advice, greatly appreciated. Thanks, Steve.
It seems some setting is wrong.
Try this in your routes:
match '/404', to: 'errors#not_found', via: :all (match instead of get)
You mention that in application.rb you have config.exceptions_app = self.routes, that is good. But make sure you are restarting the server before testing your changes.
And make sure your error views files have the same name than the actions in your ErrorsController.
If you are getting any kind of (haha) error in the console, could you post it?
Do this instead:
routes.rb
%w(404 422 500).each do |code|
get code, :to => "errors#show", :code => code
end
errors_controller.rb
class ErrorsController < ApplicationController
def show
render status_code.to_s, :status => status_code
end
protected
def status_code
params[:code] || 500
end
end
inside your config/application.rb ensure you have:
module YourWebsite
class Application < Rails::Application
config.exceptions_app = self.routes
# .. more code ..
end
end
Then you will need the views, obviously ;) don't forget to remove the error pages in your public directory as well.
I am working on a Rails app. In my app, if I enter a custom route manually in the address bar/ as URL which is not present in config/routes.rb, it will show up the below given error message.
Routing Error
No route matches "/clientImage/blablahblah"
I want this to be redirected to a proper display for all the wrong routes given by the user either intentionally/unintentionally. Any help would be greatly appreciated.
When someone enters unsupported url Rails will raise ActionController::RoutingError. You can rescue this error and render 404 Not Found html.
Rails provides some special function called rescue_from for this purpose.
class ApplicationController < ActionController::Base
rescue_from ActionController::RoutingError, :with => :render_not_found
rescue_from StandardError, :with => :render_server_error
protected
def render_not_found
render "shared/404", :status => 404
end
def render_server_error
render "shared/500", :status => 500
end
end
Put your 404.html, 500.html in app/views/shared
Yourapp::Application.routes.draw do
#Last route in routes.rb
match '*a', :to => 'errors#routing'
end
The "a" is actually a parameter in the Rails 3 Route Globbing technique. For example, if your url was /this-url-does-not-exist, then params[:a] equals "/this-url-does-not-exist". So be as creative as you'd like handling that rogue route.
In app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
def routing
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
end
end
I have one rails application in which I have two sections, so I want to use two different layouts for the Error page.
For example, if an error is coming from Section 1 then layout1 / different page should be used for the Error (404, 500).
If error is coming from Section 2 then layout2 / different page should be used for the Error (404, 500).
I've written code to define the Error page, enabled with erb and ruby code.
in application.rb
config.exceptions_app = self.routes
in routes.rb
match "/404", :to => "errors#error_404"
match "/500", :to => "errors#error_500"
Updated
Thought about it a little. If you only have a few types of errors, how about doing it like this?
In your routes.rb, at the very last line, add a
match '/my_segment/*path', :to => 'errors#not_found'
This should match any path that is not defined (which normally throws ActionController::RoutingError) and push it to your global error page.
You can play with play with the segments wildcard above to get your correct path. This should NOT affect your predefined paths, like mydomain.com/controller1.
Below is a more fine grained method of control.
This will help you match any errors from mydomain.com/some_controller/bad_params
def firstController < ApplicationController
def method_in_first_controller
# Do something here
rescue
#error = # Error object here
render :template=>"some_error_template", :status => :not_found # In specific action
end
end
def secondController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, :with => :rescue_not_found # In secondController
def method_in_second_controller
# Do something
end
protected
def rescue_not_found
#error = # Error object here
render :template => 'some_error_template', :status => :not_found
end
end
def ApplicationController
rescue_from ActiveRecord::RecordNotFound, :with => :rescue_not_found # Globally
protected
def rescue_not_found
#error = # Error object here
render :template => 'application/not_found', :status => :not_found
end
end
Using referrer doesn't seem to get anywhere, sorry for the bad answer yesterday.
In your errors controller you can have a check who is the referrer and have a conditional layout based on that
i was wondering if i could add an exception to route globbing in rails. in my routes.rb i have
unless params[:not_found].eql? 'admin_data'
match '*not_found', to: 'errors#error_404'
end
im trying to enforce custom error pages, except when a user visits
myapp.heroku.com/admin_data
it doesn't seem like fetching :not_found as a param works. is there a way to add an exception in routes.rb?
if it helps, in my errors_controller i have..
def error_404
#not_found_path = params[:not_found]
end
thank you
update.
i tried doing just
puts :not_found
puts %{not_found}
but doesn't seem to work either hmmm...im trying to see if i can retrieve the params from the user
It would be much more convenient to define allowed routes in routes.rb and add exception handling in application controller for routing error:
class ApplicationController < ActionController::Base
rescue_from ActionController::RoutingError, :with => :render_not_found
private
def render_not_found
render_error_page_for(404)
end
def render_error_page_for(code)
respond_to do |format|
format.html { render :file => "#{Rails.root}/public/#{code}.html", :status => code, :layout => false }
end
end
i do catch my exception handling in my application controller but unfortunately for admin_data, i don't explicitly set it in routes.rb. it gets configured somewhere in the gem with namespace or something (im not really sure)
but on a positive note... i finally fixed it! i changed my glob and did...
match '*not_found', to: 'errors#error_404', :constraints => {:subdomain => "!(admin_data.)"}
to ignore everything which uses admin_data.