目前我在我的观点中进行了一些计算,当然这是一件坏事:
<% categories.each do |c| %>
....
<%= c.transactions.sum("amount_cents") %>
....
<% end %>
我正在研究能够帮助我重构上述问题的方法。
有一件事是将计算移动到我的控制器
@category_sum = @transaction.sum("amount_cents")
这可能是更好的解决方案,但你知道。不完美。
由于我有很多用户,我不知道如何将计算器逻辑移动到我的模型中。所以我想我可能需要使用一个新的类,创建一堆方法(总和,平均等)并在视图中使用它们?我是在正确的轨道上吗?非常感谢有关如何重构我的代码以及设计和实现此类的任何建议。
答案 0 :(得分:9)
隔离视图逻辑的一个意思是使用演示者。
演示者允许您执行类似的操作:
<% categories.each do |c| %>
....
<% present c do |category| %>
<%= category.transaction_sum %>
<% end %>
....
<% end %>
然后您在app/presenters/category_presenter.rb
中有一个演示者课程:
class CategoryPresenter < BasePresenter
presents :category
def transaction_sum
category.transactions.sum("amount_cents")
end
end
当然,如果您在该演示者中有许多方法,最好使用它(但是一旦开始减少视图逻辑,就可以快速填充演示者)。
此处使用的实现依赖于this pro railscast中描述的内容。基本思路就是拥有一个#present
助手,根据对象类推断出一个类名,加载并初始化正确的演示者类。
另一种流行的替代方法是使用drapper,它使用装饰器的概念,但是演示者基本上是装饰者。
答案 1 :(得分:2)
你看到的主要代码气味被称为the law of Demeter(就像许多编程“法律”一样,你应该把它看作更像“得墨忒耳的指南”)。
您可以做的是将实际计算步骤移到类别上的方法中,例如
class Category < ActiveRecord::Base
def transaction_amount
transactions.sum("amount_cents")
end
end
<% categories.each do |c| %>
....
<%= c.transaction_amount %>
....
<% end %>
从技术上讲,在渲染视图时仍然会执行计算,但是计算总和量的如何的逻辑不再位于视图本身内部。现在所关注的所有视图都是它可以将消息transaction_amount
发送到类别对象。这也为您提供了为总和添加缓存的空间,或者您可以停止传递实际记录,而是传递静态对象(不是ActiveRecord模型),这些对象来自执行总和的某些代码。更有效率的方式。