How to controller the error message displayed in Rails 5? - ruby-on-rails

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

Related

Rails dynamic error pages (404, 422, 500) showing as blank

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.

Rails 4 and JSON routing returns error in Firebug

I have implemented an AJAX call that renders a JSON response.After checking my Firebug Console, I can see that the call results in a 404 Not Found error.
In my Controller (test_rules_controller.rb)
def rule_attributes
#test = RuleModel.find(params[:rule_model_id]).rule_attributes
respond_to do |format|
format.json { render :json => #test }
end
end
In my Routes:
get "/rule_models/:rule_model_id:/rule_attributes" => "test_rules#rule_attributes", :as => "rule_attributes", :format => :json
I have also created a rule_attributes.json.jbuilder file in my test_rules view folder:
json.rule_attributes #test
I am not sure why it is resulting in this error as I've never used JSON with routes before (Rails Newbie). When I try to navigate to the same URL in the browser, it raises the error that no route matches the given route (http://localhost:3000/rule_models/1/rule_attributes.json).
Can anybody please help?

Show a 404 instead of 500 in Rails

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.

Custom Error Pages in Rails?

I need to implement a custom error page in my rails application that allows me to use erb.
I've been following this tutorial (http://blog.tommilewski.net/2009/05/custom-error-pages-in-rails/) and I cannot get it to work locally (or remotely). I am running Rails 2.3.5
Here's the gist of the approach.
1) in the 'application_controller', I over ride the "render_optional_error_file(status_code)" method, and set the visibility to "protected", like this.
protected
def render_optional_error_file(status_code)
known_codes = ["404", "422", "500"]
status = interpret_status(status_code)
if known_codes.include?(status_code)
render :template => "/errors/#{status[0,3]}.html.erb", :status => status, :layout => 'errors.html.erb'
else
render :template => "/errors/unknown.html.erb", :status => status, :layout => 'errors.html.erb'
end
end
def local_request?
true
end
I also created a folder within views called errors and created the following views: 404.html.erb, 422.html.erb, 500.html.erb,unknown.html.erb and I created a new layout "errors.html.erb"
I can't seem to get it to work. I've been trying to trigger the 404 page by navigating to http://localhost:3000/foobar -- but, instead of getting the new 404.html.erb, I seem to be getting the standard apache 500 error. This happens when I try both mongrel_rails start and mongrel_rails start -e production.
I would suggest using exceptions to render such error pages, so you can use inheritance to group your error messages...
First, declare some (I usually do it in application_controller.rb)
class Error404 < StandardError; end
class PostNotFound < Error404; end
Then add code to ApplicationController to handle them
class ApplicationController < ActionController::Base
# ActionController::RoutingError works in Rails 2.x only.
# rescue_from ActionController::RoutingError, :with => :render_404
rescue_from Error404, :with => :render_404
rescue_from PostNotFound, :with => :render_post_not_found
def render_404
respond_to do |type|
type.html { render :template => "errors/error_404", :status => 404, :layout => 'error' }
type.all { render :nothing => true, :status => 404 }
end
true
end
def render_post_not_found
respond_to do |type|
type.html { render :template => "errors/shop_not_found", :status => 404, :layout => 'error' }
type.all { render :nothing => true, :status => 404 }
end
true
end
end
This renders errors/error_404 with the errors layout. Should get you started :)
And in your target_controller:
raise PostNotFound unless #post
Edit
Note for Rails 3
for a longer explanation on why ActionController::RoutingError doesn't work for rails 3:
Rails 3.0 Exception Handling.
Rails ticket 4444
"If your application relies on engines that extend your app with their
own routes, things will break because those routes will never get
fired!"
Firstly - have you deleted the file: 'public/500.html' If that file exists, it will override anything else that you try to do.
Secondly, using an explicit "rescue_from" in the controller (as explained in the other comment) - is a good option if you need to fine-tune the response to different kinds of errors.
You most likely get the 500 error because of an application error.
Have you checked the log files?
Update:
Are you certain that you are running 2.3.5 and not an older version that happens to be installed?
Mongrel should say which version you are running when it starts, otherwise it should say in the config/environment.rb file.
There are some errors in the code that might create the 500 error. I've changed that and also corrected a few other things I think you meant :)
def render_optional_error_file(status_code)
known_codes = ["404", "422", "500"]
status = interpret_status(status_code)
if known_codes.include?(status) # Here it should be status, not status_code (which is a symbol)
render :template => "errors/#{status[0,3]}", :status => status, :layout => 'errors' # No need to mention ".html.erb", you can do it, but it is not necessary since rails will guess the correct format.
else
render :template => "errors/unknown", :status => status, :layout => 'errors'
end
end
def local_request?
# This must return false instead of true so that the public viewer is called
# instead of the developer version.
false
end
Purpose of completeness for newer rails versions:
http://www.frick-web.com/en/blog/nifty_errorpages-gem
that is a little rails engine for handling your error pages. Maybe you will need it for newer projects. it is a good option to handle errors in my opinion.

How do you issue a 404 response from a rails controller action?

What's the preferred way to issue a 404 response from a rails controller action?
This seems good...
# Rails 2 and below
render :file => "#{RAILS_ROOT}/public/404.html", :status => 404
# Rails 3 and up
render :file => "#{Rails.root}/public/404.html", :status => 404
You can also
raise ActiveRecord::RecordNotFound
exception.
The following way was the best for me:
raise ActionController::RoutingError.new('Not Found')
or just
raise ActionController::RoutingError, 'Not Found'
Or there are some other solutions:
How to redirect to a 404 in Rails?
Reference:
render :file => '/path/to/some/filenotfound.rhtml',
status => 404, :layout => true
In the ApplicationController define a method like:
def render_404
render :file => "#{RAILS_ROOT}/public/404.html", :status => 404
end
In Rails 5 you can use
head 404
This will set the response code of your action to 404. If you immediately return after this from your action method, your action will respond 404 with no actual body. This may be useful when you're developing API endpoints, but with end user HTTP requests you'll likely prefer some visible body to inform the user about the error.
If you wanted to issue a status code on a redirect (e.g. 302), you could put this in routes.rb:
get "/somewhere", to: redirect("/somewhere_else", status: 302).
However, this would only work for redirection, not straight up loading a page.

Resources