Custom Error Handling with Rails 4.0

拈花ヽ惹草 提交于 2019-11-30 01:59:24

The request isn't even hitting your app.

You need to define a catchall route so Rails will send the request to your app rather than display an error (in development) or render the public/404.html page (in production)

Modify your routes.rb file to include the following

match "*path", to: "errors#catch_404", via: :all

And in your controller

class ErrorsController < ApplicationController

  def catch_404
    raise ActionController::RoutingError.new(params[:path])
  end
end

And your rescue_from should catch the error then.

After trying a few variations I've settle on this as the simplest way to handle the API 404s:

# Passing request spec
describe 'making a request to an unrecognised path' do
  before { host! 'api.example.com' }
    it 'returns 404' do
    get '/nowhere'
    expect(response.status).to eq(404)
  end
end

# routing
constraints subdomain: 'api' do
  namespace :api, path: '', defaults: { format: 'json' } do
    scope module: :v1, constraints: ApiConstraints.new(1) do
      # ... actual routes omitted ...
    end
    match "*path", to: -> (env) { [404, {}, ['{"error": "not_found"}']] }, via: :all
  end
end

this works in rails4, this way you can manage directly all errors: for example you can render error_info as json when an an error occurs from an api call..

application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery


  # CUSTOM EXCEPTION HANDLING
  rescue_from StandardError do |e|
    error(e)
  end

  def routing_error
    raise ActionController::RoutingError.new(params[:path])
  end

  protected

  def error(e)
    #render :template => "#{Rails::root}/public/404.html"
    if env["ORIGINAL_FULLPATH"] =~ /^\/api/
    error_info = {
      :error => "internal-server-error",
      :exception => "#{e.class.name} : #{e.message}",
    }
    error_info[:trace] = e.backtrace[0,10] if Rails.env.development?
    render :json => error_info.to_json, :status => 500
    else
      #render :text => "500 Internal Server Error", :status => 500 # You can render your own template here
      raise e
    end
  end

  # ...

end

routes.rb

MyApp::Application.routes.draw do

  # ...

  # Any other routes are handled here (as ActionDispatch prevents RoutingError from hitting ApplicationController::rescue_action).
  match "*path", :to => "application#routing_error", :via => :all
end
noelvictorino

I used the 404.html from public folder and this is in dev environment.
I actually got the answer from:

However, I did a little experiment on what pieces of code actually made it work. Here's are the pieces of code that I only added.

config/routes.rb

Rails.application.routes.draw do
    // other routes
    match "*path", to: "application#catch_404", via: :all
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
    def catch_404
        render :file => 'public/404.html', :status => :not_found
    end
end

Will appreciate any comments and clarifications as to why some of the original are are needed. For instance, using this line of code

raise ActionController::RoutingError.new(params[:path])

and this

rescue_from ActionController::RoutingError, :with => :error_render_method

Because rescue_from and raise ActionController::RoutingError seem to be the popular answer from the older Rails versions.

Try this if you want respond to all types of errors in the same way

rescue_from StandardError, :with => :error_render_method

If you don't want this behavior in your development mode, add the above code under

unless Rails.application.config.consider_all_requests_local

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!