2013-04-04 32 views
7

Tôi đang tìm cách hiển thị thông báo lỗi trong chế độ xem jbuilder. Ví dụ, một tuyến đường tôi có thể có thể là:Rails cách thích hợp để hiển thị lỗi với jbuilder

/foos/:id/bars

Nếu :id gửi bởi người dùng không tồn tại hoặc không hợp lệ, tôi muốn để có thể hiển thị các thông báo lỗi tương ứng trong tập tin index.json.builder của tôi .

Sử dụng Rails, cách tốt nhất để thực hiện việc này là gì? Bộ điều khiển có thể có một cái gì đó như:

def index 
    @bar = Bar.where(:foo_id => params[:id]) 
end 

Trong trường hợp này, có thể là params[:id]nil, hoặc đối tượng mà có thể không tồn tại. Tôi không chắc liệu điều tốt nhất để làm ở đây là xử lý nó trong bộ điều khiển và hiển thị một cách rõ ràng error.json.builder hoặc xử lý nó trong chế độ xem index.json.builder. Cách chính xác để làm điều này là gì và nếu nó ở trong số index.json.builder, có phải là params[:id] để kiểm tra ở đó không? Tôi biết tôi có thể xem nếu @bar.nil? nhưng không chắc chắn về nghịch đảo?

Trả lời

4

tôi sẽ làm cho index.json.builder hoặc json chỉ inline với :error => 'not found' Và đừng quên để thiết lập trạng thái HTTP thích hợp: :status => 404

Vì vậy, kết quả có thể nhìn như thế này:

render :json => { :error => 'not found' }, :status => 422 if @bar.nil? 
4

tôi nghĩ rằng bạn có nghĩa là hiển thị, vì chỉ mục thực sự là cho danh sách/bộ sưu tập. Và bạn sẽ nhận được .first về nơi, nếu không bạn chỉ có một mối quan hệ, phải không? Sau đó, sử dụng .first! để tăng lỗi, bởi vì phần mềm trung gian Rack của Rails trong Rails 4 public_exceptions sẽ xử lý theo kiểu cơ bản, ví dụ:

def show 
    # need to do to_s on params value if affected by security issue CVE-2013-1854 
    @bar = Bar.where(:foo_id => params[:id].to_s).first! 
end 

Bạn cũng có thể sử dụng @bar = Bar.find(params[:id]), nhưng điều đó bị phản đối và sẽ được loại bỏ trong Rails 4.1, sau đó bạn sẽ phải thêm gem 'activerecord-deprecated_finders' để Gemfile của bạn để sử dụng.

Đối với chỉ mục, bạn có thể muốn @bars = Bar.all. Nếu vì một số lý do bạn muốn lọc và không muốn phạm vi, v.v, thì bạn có thể sử dụng @bars = Bar.where(...).to_a hoặc tương tự.

Rails 4: Basic Xử lý ngoại lệ trong rack là Automatic

Chừng nào truy vấn đá ra một lỗi, Rails 4 sẽ có thể trả lại một phần thông điệp của lỗi cho bất kỳ định dạng được hỗ trợ where to_(format) có thể được gọi vào băm (ví dụ: json, xml, v.v.)

Để xem lý do tại sao, hãy xem Rails 'Rack public_exceptions middleware.

Nếu là html, nó sẽ cố gắng đọc trong tệp có liên quan từ thư mục công khai trong Rails cho mã trạng thái (ví dụ: 500.html cho lỗi máy chủ/HTTP 500).

Nếu đó là một số định dạng khác, nó sẽ cố gắng làm to_(the format) trên băm: { :status => status, :error => exception.message }.Để xem cách này sẽ làm việc đi đến Rails' console:

$ rails c 
... 
1.9.3p392 :001 > {status: 500, error: "herro shraggy!"}.to_xml 
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <status type=\"integer\">500</status>\n <error>herro shraggy!</error>\n</hash>\n" 
1.9.3p392 :002 > {status: 500, error: "herro shraggy!"}.to_json 
=> "{\"status\":500,\"error\":\"herro shraggy!\"}" 

Trong middleware, bạn sẽ thấy X-Cascade tiêu đề trong mã và ở những nơi khác nhau liên quan đến Rails' xử lý ngoại lệ trong rack. Mỗi this answer, tiêu đề X-Cascade được đặt thành pass để cho Rack biết các tuyến đường khác để tìm tài nguyên.

Rails 3.2.x: Có thể xử lý ngoại lệ trong rack

Trong Rails 3.2.x, rằng mã để làm to_(format) cho cơ thể phản ứng, vv không có trong public_exceptions.rb. Nó chỉ xử lý định dạng html.

Có lẽ bạn có thể thử thay thế phần mềm trung gian cũ bằng phiên bản mới hơn qua bản vá.

Nếu bạn muốn Rack xử lý lỗi của bạn theo cách cụ thể hơn mà không cần vá, hãy xem # 3 trong bài đăng của José Valim, "My five favorite “hidden” features in Rails 3.2".

Trong đó và như another answer cũng đề cập đến, bạn có thể sử dụng config.exceptions_app = self.routes. Sau đó, với các tuyến đường trỏ đến một bộ điều khiển tùy chỉnh, bạn có thể xử lý các lỗi từ bất kỳ bộ điều khiển nào giống như bất kỳ yêu cầu nào khác. Lưu ý bit về config.consider_all_requests_local = false trong số config/environments/development.rb của bạn.

Bạn không phải sử dụng tuyến đường để sử dụng exceptions_app. Mặc dù nó có thể là một chút đáng sợ, nó chỉ là một proc/lambda mà mất một băm và trả về một mảng có định dạng là: [http_status_code_number, {headers hash...}, ['the response body']]. Ví dụ, bạn sẽ có thể làm điều này trong Rails bạn 3.2.x cấu hình để làm cho nó xử lý các lỗi như Rails 4.0 (đây là public_exceptions middleware mới nhất sụp đổ):

config.exceptions_app = lambda do |env| 
    exception = env["action_dispatch.exception"] 
    status = env["PATH_INFO"][1..-1] 
    request = ActionDispatch::Request.new(env) 
    content_type = request.formats.first 
    body = { :status => status, :error => exception.message } 
    format = content_type && "to_#{content_type.to_sym}" 
    if format && body.respond_to?(format) 
    formatted_body = body.public_send(format) 
    [status, {'Content-Type' => "#{content_type}; charset=#{ActionDispatch::Response.default_charset}", 
      'Content-Length' => body.bytesize.to_s}, [formatted_body]] 
    else 
    found = false 
    path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale 
    path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path)) 

    if found || File.exist?(path) 
     [status, {'Content-Type' => "text/html; charset=#{ActionDispatch::Response.default_charset}", 
       'Content-Length' => body.bytesize.to_s}, [File.read(path)]] 
    else 
     [404, { "X-Cascade" => "pass" }, []] 
    end 
    end 
end 

Lưu ý: Đối với bất kỳ vấn đề với việc xử lý mà , triển khai không an toàn là ở ActionDispatch::ShowExceptionshere.

Rails 3 và 4: Xử lý một số trường hợp ngoại lệ trong Rails khiển

Nếu bạn muốn có vẽ lỗi trong bộ điều khiển chính nó, bạn có thể làm:

def show 
    respond_with @bar = Bar.where(:foo_id => params[:id].to_s).first! 
rescue ActiveRecord::RecordNotFound => e 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

Tuy nhiên, bạn không cần để tăng lỗi. Bạn cũng có thể làm:

def show 
    @bar = Bar.where(:foo_id => params[:id].to_s).first 
    if @bar 
    respond_with @bar 
    else 
    respond_to do |format| 
     format.json => { :error => "Couldn't find Bar with id=#{params[:id]}" }, :status => 404 
    end 
    end 
end 

Bạn cũng có thể sử dụng rescue_from, ví dụ: trong điều khiển của bạn, hoặc ApplicationController, v.v .:

rescue_from ActiveRecord::RecordNotFound, with: :not_found 

def not_found(exception) 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

hay:

rescue_from ActiveRecord::RecordNotFound do |exception| 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

Mặc dù một số lỗi phổ biến có thể được xử lý trong điều khiển, nếu bạn sai sót liên quan đến thiếu các tuyến đường vv định dạng trong json , vv, những người cần phải được xử lý trong Rack middleware.

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