如何在多个Rails模型上执行计算,逻辑应该放在哪里?

3
我有一个发票模型在Rails应用程序中。发票拥有许多产品和服务(两个单独的模型)。发票展示视图显示这些关联记录。
产品和服务都具有类似的结构,即项目、价格、数量。我可以按 price * quantity 计算行总计,也可以按 all.collect { |product| product.price * product.quantity } 计算产品的总价,服务也是一样。
如果我现在想要计算此发票上产品和服务的总成本怎么办?
我该如何在多个模型之间执行计算?计算逻辑应该放在哪里?
我意识到一个解决方案是将产品和服务合并为一个模型,但这在这里不是一个选项。
我对此感到困惑,非常希望得到一些指导、想法或链接到有用文档。
3个回答

2
简而言之:使用模块。我想的是这样的东西:
module TotalCalculator
  def sum
     map { |e| e.price * e.quantity }
  end
end

然后您可以:

class Product
  include TotalCalculator
end

当然,这只是一个微不足道的例子,命名也很糟糕。顺便说一下,你可以看到图片。我会把所有逻辑放在app/logic目录或lib目录中。有时我称这种技术为模块作为业务逻辑模式,但我不知道这是否是一个恰当的名称。

谢谢lucapette,这是一个非常好的想法。我会再考虑一下,并尝试将其融入我的案例中。 - Andy Harvey

2

只是确认一下:

  • 发票有许多产品和服务
  • 产品有一个total_cost方法(或total_price)
  • 服务也有一个total_cost方法

你想知道在发票中放置产品和服务的总价逻辑。对吗?

在这种情况下,将其放在发票中是正确的:

def total_cost_of_products
  products.collect { |product| product.price * product.quantity }
end

def total_cost_of_services
  services.collect { |services| service.price * service.quantity }
end

def total_price_of_products_and_services
  total_cost_of_products + total_cost_of_services
end

当然,你可以更加DRY(Don't Repeat Yourself),并且可能需要在发票模型上进行一些单元测试。请查看lucapette的答案,以了解一种很好的重构和DRY的方法。

谢谢@corroded,我尝试过类似的操作,但返回了奇怪的结果。也许这是因为我的价格存储为小数而不是整数?在对小数进行计算时,我需要注意哪些问题? - Andy Harvey
现在我仔细看了一下,这个计算是将total_cost_of_products和total_cost_of_services连接起来,而不是求和。我做错了什么吗? - Andy Harvey
如果它正在连接,则您的值以某种方式作为字符串存在。我认为这值得在这里再提一个问题,因为它似乎是完全不同的问题。 - corroded
谢谢corroded,我已经将这个问题转移到http://stackoverflow.com/questions/9542975/how-to-add-bigdecimal-values-in-a-rails-app/9543011#9543011。 - Andy Harvey
顺便提一下,你可能想学习ActiveRecord Calculation方法,因为它可能会让你的生活更轻松 :) http://ar.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html - corroded

0
你能否在发票模型上创建一个虚拟属性total_cost,然后将你的代码放在里面呢?
def total_cost 
  cost = #do your calculation here....
  return cost  
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接