Rails - 从我的观点中移出计算?

时间:2013-11-15 13:47:55

标签: ruby-on-rails ruby-on-rails-4

目前我在我的观点中进行了一些计算,当然这是一件坏事:

<% categories.each do |c| %>
  ....
    <%= c.transactions.sum("amount_cents") %>
  ....
<% end %>

我正在研究能够帮助我重构上述问题的方法。

有一件事是将计算移动到我的控制器

@category_sum = @transaction.sum("amount_cents")

这可能是更好的解决方案,但你知道。不完美。

由于我有很多用户,我不知道如何将计算器逻辑移动到我的模型中。所以我想我可能需要使用一个新的类,创建一堆方法(总和,平均等)并在视图中使用它们?我是在正确的轨道上吗?非常感谢有关如何重构我的代码以及设计和实现此类的任何建议。

2 个答案:

答案 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模型),这些对象来自执行总和的某些代码。更有效率的方式。