如何在rails中冒出异常

时间:2013-02-04 02:52:21

标签: ruby-on-rails error-handling

新的rails并遇到围绕最佳实践错误处理的一些问题。

我在/ lib文件夹中的helper中有以下代码,用于将优惠券应用于某些定价。

正如您从下面的代码中可以看到的,我正在尝试一些不同的方法来返回任何错误。具体来说,是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

1 个答案:

答案 0 :(得分:3)

我认为你走在正确的轨道上,但是你正在努力,因为你正在将视图逻辑与业务逻辑混合在一起。 忘记帮助程序类并将功能添加到模型中。

通过将验证添加到模型而不是辅助类并将错误添加到基础控制器操作将能够在尝试以正常方式保存/创建记录时处理错误,从而“冒泡”错误“

e.g。

    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 %>

正如我之前所说,因为验证是在模型中添加的,那么你的控制器操作只需要检查保存的调用值,如果它返回false则正常闪烁错误,所以不需要在控制器中做任何自定义操作行动。只是默认的脚手架行为。

您可以使用大量验证选项。看一下 http://guides.rubyonrails.org/active_record_validations_callbacks.html

希望这是有道理的。

对评论作出回应的最新消息

1)你有很多地方。这只是一个建议,你可以计算交易价格作为验证的一部分。如果这不符合您的要求,那就没关系。我只是想让你最适合你的问题。问题是你应该有两个单独的实例方法然后你可以从任何你想要的地方调用它们,这使得它更容易实验和移动东西。使用您建议的解决方案这很好:))

2)仔细查看脚手架控制器和视图。您将看到保存/更新如何失败(如果您在验证过程中添加错误,它们将自动失败)使用if语句,您将看到_form partial如何显示错误

这是一个处理我正在处理的应用中的引擎的表单示例。

<%= 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 %>

基本上它正在检查错误并循环显示所有错误(如果有的话)以显示它们。

要处理Flash消息,您应该使用应用程序主布局 以下代码将在名为“info”的div中显示flash消息,您可以根据需要设置样式

  <% 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消息,那么您可能不需要显示错误。有时两者都是正确的事情,有时只有一个或另一个是好的。这取决于你根据具体情况决定。

主要的是,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 忘记提到flash只是一个哈希并使用会话cookie,所以你可以设置你喜欢的任何键 e.g。

flash.now[:fred]

如果您希望使用与应用程序布局提供的样式不同的样式,则可以在特定视图中设置样式并处理特定的fred通知,方法是添加代码以处理:fred键(或您选择的名称)特定观点