2013-02-04 50 views
3

新手入門並遇到一些圍繞最佳實踐錯誤處理的問題。如何在rails中引發異常

我在/ lib文件夾中的幫助程序中有以下代碼,用於將優惠券應用於某些定價。

正如你可以從下面的代碼看到的,我嘗試了幾種不同的方式來返回任何錯誤。具體來說,model.errors.add和flash [:error]。

下面的代碼應該會返回一個新的價格,一旦有效的優惠券已被應用。我不確定的是在出現錯誤的情況下返回什麼?我不能在下面返回false,因爲這個方法應該真的返回一個數值,而不是布爾值。從lib/helper的視圖中冒出錯誤並停止執行的最佳方法是什麼?

def calc_coupon transaction_price, discount_code, current_tenant 
    coupon = Coupon.where(code: discount_code, tenant_id: current_tenant.id).first 

    if coupon.nil? 
    current_tenant.errors.add :base, "No such coupon exists" 
    return false 
    else 
    if coupon.maxed? || coupon.expired? 
     flash[:error] = "This coupon is no longer valid." 
     return false 
    else 
     transaction_price = coupon.calculate(transaction_price) 
    end 
    end 
    return transaction_price 
end 
+0

也許你想分開驗證部分和transaction_price計算。部分? http://guides.rubyonrails.org/active_record_validations_callbacks.html#custom-validators – kukrt

回答

3

我認爲你是在正確的軌道上,但是你在掙扎,因爲你正在將視圖邏輯與業務邏輯混合在一起。 忘掉助手類並將功能添加到模型中。

通過將驗證添加到模型而不是輔助類並添加錯誤到基礎控制器操作將能夠處理錯誤,當它試圖以正常方式保存/創建記錄,因此「冒泡錯誤「

eg

class MyModel < ActiveRecord ... 
     validate :validate_coupon 
     protected 
     def validate_coupon 
#   add your validations here - call your boolean check which adds errors to the model 
#   if validations are ok then calculate your transaction price here 
     end 
    end 

如果你有你的支票作爲模型的公共方法,然後他們可以從任何地方調用,從視圖 等模型公共transaction_price方法,首先檢查錯誤,並設置可以在價格之內即在視圖中使用像這樣

<%= @some_object.transaction_price %> 

正如我前面所說,因爲驗證在模型中,然後你的控制器動作只需要檢查呼叫的價值保存和閃光的錯誤,因爲正常的,如果它返回添加假所以不需要在你的控制器動作中進行任何自定義操作。只是默認的腳手架行爲。

有一大堆驗證選項可供您使用。看看 http://guides.rubyonrails.org/active_record_validations_callbacks.html

希望是有道理的。

更新所發表​​評論

1)您有在幾乎當場。這只是一個建議,您可以將交易價格作爲驗證的一部分進行計算。如果這不符合你的要求,那很好。我只是想給你最適合你的問題。問題是你應該有兩種獨立的實例方法,然後你可以從任何地方調用它們,這使得它更容易實驗和移動。去你的建議的解決方案這是很好:)

2)仔細看看腳手架的控制器和意見。您將看到如何使用if語句,保存/更新失敗(如果您在驗證過程中添加錯誤,它們將自動失敗),您將看到_form部分如何顯示錯誤

這是一個示例表單處理我正在處理的應用程序中的引擎。

<%= form_for(@engine) do |f| %> 
    <% if @engine.errors.any? %> 
    <div id="error_explanation"> 
     <h2><%= pluralize(@engine.errors.count, "error") %> prohibited this engine from being saved:</h2> 

     <ul> 
     <% @engine.errors.full_messages.each do |msg| %> 
     <li><%= msg %></li> 
     <% end %> 
     </ul> 
    </div> 
    <% end %> 

基本上它是檢查錯誤並循環遍歷它們,如果有的話顯示它們。

要處理的提示信息,你應該利用應用主要佈局 下面的代碼會顯示一個名爲「信息」 DIV中的提示信息,你可以風格,但是你想

<% unless flash.empty? %> 
    <div class="info"> 
    <%- flash.each do |name, msg| -%> 
     <%= content_tag :div, msg, :id => "flash_#{name}" %> 
    <%- end -%> 
    </div> 
    <% end %> 

通過將之前的主在您的views/layouts文件夾中的application.html.erb中,您可以確保無論顯示哪個頁面,都會向用戶顯示Flash消息

當然,如果您正在顯示Flash消息,那麼也許你不會; t需要顯示錯誤。有時候兩者都是正確的做法,有時候只有一種是好的。這取決於您是否根據具體情況來決定。

最主要的是,HTTP POST或HTTP PUT(創建或更新操作)的接收操作可處理無論是否存儲閃存的故障,如您認爲合適的 創建操作

def create 
    @engine = Engine.new(params[:engine]) 

    respond_to do |format| 
     if @engine.save 
     format.html { redirect_to @engine, notice: 'Engine was successfully created.' } 
     format.json { render json: @engine, status: :created, location: @engine } 
     else 
     flash.now[:notice] = "Failed to save!" # flash.now because we are rendering. flash[:notice] if using a redirect 
     format.html { render action: "new" } 
     format.json { render json: @engine.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

。希望清除的東西了

更新2 忘了提,閃光只是一個哈希,並使用會話cookie,所以你可以設置任意鍵你喜歡 例如

flash.now[:fred] 

這將使你的風格和特定視圖處理一個特定的弗雷德通知,如果你通過添加代碼來處理想從你的應用程序佈局提供不同的造型:弗雷德鍵(或名稱你的選擇)在一個特定的視圖

+0

感謝您的詳細回覆。如果你不介意的話,我有幾個跟進問題。 1.你說我應該計算'validate_coupon'自定義驗證器中的交易價格。這不應該在實例方法中完成嗎?如果是這樣,我會做一些像'if @ coupon.valid?價格= @ coupon.calc_price(orginal_price)'2.用戶輸入優惠券的形式不是優惠券的支架,而是支付形式。如果我向模型添加錯誤,它們將如何在此表單上顯示?再次感謝您的洞察力! – cman77

+0

@ cman77查看更新的答案 – jamesc

+0

這很棒 - 非常感謝您的詳細回覆! – cman77