2012-11-17 28 views
14

Tôi đã tình cờ gặp một tình huống mà ứng dụng của tôi tìm kiếm một id không tồn tại trong cơ sở dữ liệu. Một ngoại lệ được ném. Tất nhiên, đây là một tình huống khá chuẩn đối với bất kỳ nhà phát triển web nào.Giải cứu chung trên toàn bộ bộ điều khiển khi không tìm thấy id - RoR

Nhờ this answer Tôi biết rằng việc sử dụng giao dịch cứu hộ với tình hình khá gọn gàng, như vậy:

def show 
    @customer = Customer.find(params[:id]) 
    rescue ActiveRecord::RecordNotFound #customer with that id cannot be found 
    redirect_to action: :index  #redirect to index page takes place instead of crashing 
end 

Trong trường hợp khách hàng không thể được tìm thấy, người dùng được chuyển hướng đến trang index. Điều này hoạt động hoàn toàn tốt đẹp.

Bây giờ, mọi thứ đều tốt đẹp, nhưng tôi cần thực hiện các nỗ lực cứu hộ tương tự như hiển thị, chỉnh sửa, tiêu diệt, v.v. mỗi phương pháp điều khiển cần một id cụ thể.

Có nói rằng, đây là câu hỏi của tôi: không Có cách nào để thường nói với bộ điều khiển của tôi rằng nếu nó không thể tìm thấy id trong bất kỳ các phương pháp của nó, nó sẽ chuyển hướng đến trang chỉ mục (hoặc , nói chung, thực hiện một nhiệm vụ cụ thể)?

Trả lời

31

Bạn phải sử dụng rescue_from cho nhiệm vụ này. Xem ví dụ trong Action Controller Overview Guide

class ApplicationController < ActionController::Base 
    rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found 

    private 

    def record_not_found 
    redirect_to action: :index 
    end 
end 
+1

Tuyệt vời, điều đó thực hiện mẹo, cảm ơn bạn! Trong sự tò mò: tại sao phương pháp đó nên riêng tư? – weltschmerz

+1

Chỉ cần cho sự sạch sẽ: phương pháp không cần phải được hiển thị cho các bộ điều khiển khác, đó là lý do tại sao nó được khai báo riêng. Nó sẽ hoạt động bình đẳng nếu phương thức không được khai báo riêng. – Baldrick

+2

Bạn cũng có thể thêm thông báo flash flash [: notice] = "Không tìm thấy bản ghi" –

8

Rails đã tích hợp phương pháp rescue_from lớp:

class CustomersController < ApplicationController 
    rescue_from ActiveRecord::RecordNotFound, with: :index 
    ... 
end 
+0

Điều này rất thanh lịch. Tôi đã thử nó, nhưng nó để lại cho tôi một trang trống trong trình duyệt, và trong url nó vẫn nói 'khách hàng /: id'. Tui bỏ lỡ điều gì vậy? Nó xuất hiện với tôi nó cố gắng để làm cho chỉ số thay vì chuyển hướng đến nó. – weltschmerz

+0

Bạn nói đúng .. hãy thử một cái gì đó giống như những gì Baldrick gợi ý dưới đây (tức là, một phương pháp trung gian với một chuyển hướng). –

1

Trong một số trường hợp, tôi sẽ khuyên bạn nên sử dụng Model.find_by_id(id) như trái ngược với Model.find(id). Thay vì ném một ngoại lệ, .find_by_id trả về nil. nếu không thể tìm thấy bản ghi.

Chỉ cần đảm bảo kiểm tra nils để tránh NoMethodError!

P.S. Đối với những gì nó có giá trị, Model.find_by_id(id) là chức năng tương đương với Model.where(id: id), mà sẽ cho phép bạn xây dựng một số mối quan hệ bổ sung nếu bạn muốn.

3

Nếu bạn đang nói về việc này trong vòng một bộ điều khiển duy nhất (như trái ngược với thực hiện điều này trên toàn cầu trong mỗi controller) thì đây là một vài lựa chọn:

Bạn có thể sử dụng một before_filter để thiết lập tài nguyên của bạn:

class CustomerController < ApplicationController 
    before_filter :get_customer, :only => [ :show, :update, :delete ] 

    def show 
    end 

    private 

    def get_customer 
    @customer = ActiveRecord.find(params[:id]) 
    rescue ActiveRecord::RecordNotFound 
     redirect_to :action => :index 
    end 
end 

Hoặc bạn có thể sử dụng phương pháp thay thế. Tôi đã di chuyển theo hướng này thay vì sử dụng các biến mẫu bên trong chế độ xem và điều này cũng sẽ giúp bạn giải quyết vấn đề của mình:

class CustomerController < ApplicationController 
    def show 
    # Uses customer instead of @customer 
    end 

    private 

    def customer 
    @customer ||= Customer.find(params[:id]) 
    rescue ActiveRecord::RecordNotFound 
     redirect_to :action => :index 
    end 
    helper_method :customer 
end 
+0

Từ "toàn cầu" thu hút sự chú ý của tôi. Có cách nào để làm điều này trong tất cả các bộ điều khiển? Điều đó sẽ cực kỳ hữu ích. – weltschmerz

+1

Tôi nghĩ rằng để làm những gì tôi mô tả một cách toàn cầu có thể yêu cầu một chút lập trình meta. Nhưng chỉ cần giải cứu ActiveRecord :: RecordNotFound trên toàn cầu, bạn có thể sử dụng rescue_from trong ApplicationController của mình. – bratsche

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