2013-08-21 31 views
15

Tôi đang xây dựng một api Ruby on Rails bằng Ruby 2.0 và Rails 4.0. Ứng dụng của tôi hầu như chỉ là một API JSON, vì vậy nếu xảy ra lỗi (500, 404), tôi muốn nắm bắt lỗi đó và trả về một thông báo lỗi JSON được định dạng độc đáo.Xử lý lỗi tùy chỉnh với Rails 4.0

Tôi đã thử this và cũng:

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 

Trong ApplicationController tôi.

Cả hai đều không thực hiện thủ thuật này (ngoại lệ không bị bắt). Googling của tôi cho thấy rằng điều này đã thay đổi rất nhiều giữa 3,1, 3,2, và tôi không thể tìm thấy bất kỳ tài liệu hướng dẫn tốt về cách làm điều này trong Rails 4.0.

Có ai biết không?

Sửa Dưới đây là stack trace khi tôi đi đến một trang 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) 

Tôi không nghĩ rằng tôi muốn nó bao giờ có được điều này đến nay, một cái gì đó nên bắt nó và trả lại json thích hợp phản hồi lỗi.

+0

Hmmmm, điều này thực sự có thể hoạt động như thế nào tôi đã thiết lập nó ... Hãy để tôi thử nghiệm thêm một số tính năng khác. –

Trả lời

0

Hãy thử điều này nếu bạn muốn ứng phó với tất cả các loại lỗi trong cùng một cách

rescue_from StandardError, :with => :error_render_method

Nếu bạn không muốn hành vi này trong chế độ phát triển của bạn, thêm đoạn mã trên dưới

unless Rails.application.config.consider_all_requests_local

+1

Điều cần biết, nhưng có vẻ như điều này không bắt được lỗi nào cả (tôi đã thêm một dấu vết ngăn xếp). "Error_render_method" của tôi không bao giờ được gọi. –

+0

Tôi đang sử dụng đường ray 3.2.13 và nó hoạt động cho tôi. Có thể họ đã thay đổi một cái gì đó xung quanh này trong đường ray 4 – usha

+0

Điều này sẽ không được gọi trong vài trường hợp khác nhau nếu bạn bao gồm nó trong ActionController của bạn sai. Từ các tài liệu: "Trình xử lý của lớp đầu tiên mà exception.is_a? (Klass) giữ đúng là cái được gọi, nếu có" – WattsInABox

9

hoạt động trong đường ray4, theo cách này bạn có thể quản lý trực tiếp tất cả các lỗi: ví dụ: bạn có thể hiển thị error_info như json khi xảy ra lỗi từ cuộc gọi 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

Yêu cầu thậm chí còn không được chạm ứng dụng của bạn.

Bạn cần phải xác định một lộ trình catchall nên Rails sẽ gửi yêu cầu đến ứng dụng của bạn chứ không phải hiển thị một lỗi (đang phát triển) hoặc làm cho công trang/404.html (trong sản xuất)

Sửa đổi tuyến đường của bạn. tập tin rb để bao gồm

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

Và trong điều khiển của bạn

class ErrorsController < ApplicationController 

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

Và bạn rescue_from nên bắt lỗi sau đó.

+1

Bạn có thể muốn thay đổi 'get' trong các tuyến thành' match', vì điều này cũng có thể xảy ra đối với các phương thức yêu cầu khác. – dylanfm

+0

Đúng, đã chỉnh sửa. Cảm ơn! – silasjmatson

+1

Rails 4 sẽ nhắc bạn "phơi bày hành động của bạn cho cả GET và POST, [by] thêm [ing]' qua: [: get,: post] '" - nhớ cũng làm như vậy! :) – sameers

14

Sau khi thử một vài biến thể tôi đã giải quyết về vấn đề này như là cách đơn giản nhất để xử lý các 404s API:

# 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 để giữ nó trong tệp tuyến đường và thêm thử nghiệm. Tôi đã sử dụng nhiều hoặc ít nguyên văn trong ứng dụng của mình, cảm ơn! –

1

tôi đã sử dụng 404.html từ thư mục công cộng và điều này là trong môi trường dev.
tôi thực sự nhận được câu trả lời từ:

Tuy nhiên, tôi đã làm một chút thử nghiệm trên những gì từng phần mã thực sự làm cho nó hoạt động. Đây là những đoạn mã mà tôi chỉ thêm vào.

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 

Sẽ đánh giá cao bất kỳ ý kiến ​​và giải thích vì sao một số tài liệu gốc là cần thiết . Ví dụ, sử dụng dòng mã này

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

và điều này

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

rescue_fromraise ActionController::RoutingError dường như là câu trả lời phổ biến từ các phiên bản Rails cũ.

Các vấn đề liên quan