2013-08-21 2 views
15

Я строю Ruby on Rails api с помощью Ruby 2.0 и Rails 4.0. Мое приложение является почти единственным JSON API, поэтому, если возникает ошибка (500, 404), я хочу зафиксировать эту ошибку и вернуть хорошо отформатированное сообщение об ошибке JSON.Пользовательская обработка ошибок с Rails 4.0

Я попытался this, а также:

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

def error_render_method 
    puts "HANDLING ERROR" 
    render :json => { :errors => "Method not found." }, :status => :not_found 
    true 
end 

В моей ApplicationController.

Ни один из них не выполняет трюк (исключения вообще не фиксируются). Мой googling показывает, что это сильно изменилось между 3.1, 3.2, и я не могу найти хорошую документацию о том, как это сделать в Rails 4.0.

Кто-нибудь знает?

Редактировать Вот трассировки стека, когда я иду на страницу 404:

Started GET "/testing" for 127.0.0.1 at 2013-08-21 09:50:42 -0400 

ActionController::RoutingError (No route matches [GET] "/testing"): 
actionpack (4.0.0) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' 
actionpack (4.0.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call' 
railties (4.0.0) lib/rails/rack/logger.rb:38:in `call_app' 
railties (4.0.0) lib/rails/rack/logger.rb:21:in `block in call' 
activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `block in tagged' 
activesupport (4.0.0) lib/active_support/tagged_logging.rb:25:in `tagged' 
activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `tagged' 
railties (4.0.0) lib/rails/rack/logger.rb:21:in `call' 
actionpack (4.0.0) lib/action_dispatch/middleware/request_id.rb:21:in `call' 
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call' 
rack (1.5.2) lib/rack/runtime.rb:17:in `call' 
activesupport (4.0.0) lib/active_support/cache/strategy/local_cache.rb:83:in `call' 
rack (1.5.2) lib/rack/lock.rb:17:in `call' 
actionpack (4.0.0) lib/action_dispatch/middleware/static.rb:64:in `call' 
railties (4.0.0) lib/rails/engine.rb:511:in `call' 
railties (4.0.0) lib/rails/application.rb:97:in `call' 
rack (1.5.2) lib/rack/lock.rb:17:in `call' 
rack (1.5.2) lib/rack/content_length.rb:14:in `call' 
rack (1.5.2) lib/rack/handler/webrick.rb:60:in `service' 
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/httpserver.rb:138:in `service' 
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/httpserver.rb:94:in `run' 
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/server.rb:295:in `block in start_thread' 


Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms) 
Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/routes/_route.html.erb (2.9ms) 
Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/routes/_route.html.erb (0.9ms) 
Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/routes/_table.html.erb (1.1ms) 
Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (38.3ms) 

Я не думаю, что я хочу, чтобы это когда-нибудь далеко, то надо поймать его и вернуть соответствующий JSON ответ ошибки.

+0

Хмммм, это действительно может работать, как у меня есть настройка ... Позвольте мне проверить его еще немного. –

ответ

0

Попробуйте это, если вы хотите ответить на все типы ошибок таким же образом

rescue_from StandardError, :with => :error_render_method

Если вы не хотите этого в вашем режиме разработки, добавьте приведенный выше код под

unless Rails.application.config.consider_all_requests_local

+1

Полезно знать, но похоже, что это вообще не ловут ошибку (я добавил трассировку стека). Мой «error_render_method» никогда не вызывается. –

+0

Я использую рельсы 3.2.13, и он работает для меня. Может быть, они что-то изменили в рельсах 4 – usha

+0

Это не будет вызвано в нескольких разных случаях, если вы неправильно включили его в свой ActionController. Из документов: «Обработчик первого класса, для которого true.is_a? (Klass) имеет значение true, является вызываемым, если есть какой-либо« – WattsInABox

9

это работает в rails4, таким образом вы можете управлять непосредственно всеми ошибками: например, вы можете отображать error_info как json, когда возникает ошибка при вызове api.

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 
16

Запрос даже не ударяя приложение.

Вы должны определить маршрут приема всего так Rails направит запрос к вашему приложению, а не отображать сообщение об ошибке (в разработке) или оказать 404.html страницу общественности/(в производстве)

Изменить свои маршруты. гь файл включает следующие

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

И в контроллере

class ErrorsController < ApplicationController 

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

и ваш rescue_from должен поймать ошибку тогда.

+1

Возможно, вы захотите изменить 'get' в маршрутах на' match', так как это может случиться и для других методов запросов. – dylanfm

+0

Настоящий, отредактированный. Благодаря! – silasjmatson

+1

Rails 4 напомнит вам «разоблачить свое действие как GET, так и POST, [by] добавить [ing]' через: [: get,: post] '" - не забудьте сделать это тоже! :) – sameers

14

Попробовав несколько вариантов я обосноваться на это как самый простой способ справиться с API 404-х:

# 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 
+0

+1 для сохранения в файле маршрутов и добавления теста. Я использовал это более или менее verbatim в моем приложении, спасибо! –

1

Я использовал 404.html из общей папки, и это находится в среде dev.
я фактически получил ответ от:

Однако, я сделал небольшой эксперимент на какие куски кода на самом деле сделал его работу. Вот фрагменты кода, которые я только добавил.

конфигурации/routes.rb

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

приложение/контроллеры/application_controller.rb

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

будет признателен за любые замечания и разъяснения, почему некоторые из оригинала необходимы , Например, с помощью этой строки кода

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

и это

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

Поскольку rescue_from и raise ActionController::RoutingError, кажется, популярный ответ от старых версий Rails.

Смежные вопросы