我认为您走在正确的轨道上,但您正在苦苦挣扎,因为您将视图逻辑与业务逻辑混合在一起。忘记辅助类并将功能添加到您的模型中。
通过将验证添加到模型而不是辅助类并将错误添加到基础您的控制器操作将能够在尝试以正常方式保存/创建记录时处理错误,从而“冒泡错误”
例如
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 部分如何显示错误
这是处理我正在开发的应用程序中的引擎的表单示例。
<%= 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 %>
通过将它放在 view/layouts 文件夹中 application.html.erb 的 main yield 之前,您可以确保无论呈现什么页面,flash 消息都将始终显示给用户
当然,如果您正在显示 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,因此您可以设置任何您喜欢的键,例如
flash.now[:fred]
如果您希望通过添加代码来处理特定视图中的 :fred 键(或您选择的名称)的代码与应用程序布局提供的样式不同,这将使您能够在特定视图中设置和处理特定 fred 通知的样式