我到处读到业务逻辑属于模型,而不是控制器,但是限制在哪里呢?我在玩个人会计应用程序。
Account
Entry
Operation创建操作时,只有在创建相应条目并将其链接到帐户以便操作平衡时,才有效,例如购买一个6包:
o=Operation.new({:description=>"b33r", :user=>current_user, :date=>"2008/09/15"})
o.entries.build({:account_id=>1, :amount=>15})
o.valid? #=>false
o.entries.build({:account_id=>2, :amount=>-15})
o.valid? #=>true现在,在基本操作情况下向用户显示的表单被简化,以隐藏条目的详细信息,根据用户要求的操作类型,将帐户从5个默认的帐户中选择(将帐户->权益用于会计核算、支出资产->费用、赚取收入->资产、借款负债->资产、支付债务资产->负债……)我希望从默认值创建条目。
我还希望能够创建更复杂的操作(超过2个条目)。对于第二个用例,我将有一个不同的形式,其中额外的复杂性是exposed.This,第二个用例阻止了我在操作中包括一个借方和信用字段,并去掉了条目链接。
哪一种是最好的形式?像现在一样在SimpleOperationController中使用上面的代码,或者在操作类上定义一个新方法,这样我就可以调用SimpleOperationController了
它不是打破了关注点的分离,实际上创建和操作了操作类中的条目对象吗?
(我不想就我扭曲的会计原则征求意见:)
编辑--我好像表达得不太清楚。我不太关心验证问题。我更关心的是创建逻辑代码应该去哪里:
假设控制器上的操作称为spend,当使用spend时,params散列将包含: amount、date、description。借方和贷方帐户将从被调用的操作中派生出来,但是我必须创建所有的对象。如果你能
#error and transaction handling is left out for the sake of clarity
def spend
amount=params[:operation].delete(:amount)#remove non existent Operation attribute
op=Operation.new(params[:operation])
#select accounts in some way
...
#build entries
op.entries.build(...)
op.entries.build(...)
op.save
end或者在操作上创建一个方法,使上面的内容看起来像
def spend
op=Operation.new_simple_operation(params)
op.save
end这肯定会给出一个更薄的控制器和一个更胖的模型,但是这个模型会创建和存储其他模型的实例,这正是我的问题所在。
发布于 2008-09-15 21:19:57
但是,该模型将创建和存储其他模型的实例,这正是我的问题所在。
这是怎么回事?
如果您的“业务逻辑”声明一个操作必须有一组有效的条目,那么操作类当然没有任何问题需要了解,并处理您的条目对象。
只有当你走得太远,让你的模型操纵他们不需要知道的事情时,你才会遇到问题,比如EntryHtmlFormBuilder之类的:-)
发布于 2008-09-15 21:08:43
虚拟属性(更多信息,这里和这里)将对此有很大帮助。将整个参数传递回模型,在控制器中保持简单。这将允许您动态地构建表单并轻松地构建条目对象。
class Operation
has_many :entries
def entry_attributes=(entry_attributes)
entry_attributes.each do |entry|
entries.build(entry)
end
end
end
class OperationController < ApplicationController
def create
@operation = Operation.new(params[:opertaion])
if @operation.save
flash[:notice] = "Successfully saved operation."
redirect_to operations_path
else
render :action => 'new'
end
end
end如果所有内容都无效,则保存将失败。这就给我们带来了验证。因为每个条目都是独立的,并且您需要在“创建”时检查所有条目,所以您可能应该在Operation中重写alone:
class Operation
# methods from above
protected
def validate
total = 0
entries.each { |e| t += e.amount }
errors.add("entries", "unbalanced transfers") unless total == 0
end
end现在,您将收到一条错误消息,通知用户金额已关闭,他们应修复此问题。你可以在这里得到真正的花哨,通过对问题的具体说明来增加很多价值,比如告诉他们他们有多少钱。
发布于 2008-09-15 16:23:46
从验证自身的每个实体以及相互依赖的实体将其状态委托给其关联条目的状态来考虑,这是比较容易的。例如,在你的例子中:
class Operation < ActiveRecord::Base
has_many :entries
validates_associated :entries
endvalidates_associated将检查每个关联实体是否有效(在本例中,如果操作有效,所有条目都应该有效)。
尝试验证整个模型的层次结构是很有诱惑力的,但正如您所说,最容易做到的地方是控制器,它应该更像一个请求和响应路由器,而不是处理业务逻辑。
https://stackoverflow.com/questions/64214
复制相似问题