Rails - вывод из моих представлений?

В настоящее время я выполняю некоторые вычисления в своих представлениях, что плохо, конечно:

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

Я исследую способы, которые помогут мне реорганизовать вышеупомянутую проблему.

Одно дело - переместить вычисление на мой контроллер

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

Скорее всего, это лучшее решение, но вы знаете. Не идеально.

Поскольку у меня много пользователей, я не вижу, как переместить калькулятор калькулятора в мою модель. Поэтому я думаю, мне, возможно, понадобится использовать новый класс, создать кучу методов (сумма, среднее и т.д.) И использовать их в представлениях? Я на правильном пути? Будем благодарны за любые советы о том, как реструктурировать мой код и разработать и реализовать этот класс.

Ответ 1

Однозначно изолировать логику представления - использовать презентаторов.

Ведущий позволяет вам сделать что-то вроде этого:

<% 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

Конечно, это лучше всего использовать, если у вас много методов в этом ведущем (но как только вы начинаете уменьшать логику представления, он быстро заполняет презентаторов).

Реализация, используемая здесь, основана на том, что описано в этом профи railscast. Основная идея состоит в том, чтобы иметь помощник #present, который описывает имя класса на основе класса объекта, загружает и инициализирует соответствующий класс презентатора.

Другой популярной альтернативой является использование драпиров, в которых используется концепция декоратора, но ведущий - в основном декоратор.

Ответ 2

Основной запах кода, который вы видите, называется закон Деметры (который, как и многие "законы программирования", вы должны думать это больше похоже на "руководство Деметры" ).

Что вы можете сделать, это перевести фактический шаг вычисления в метод в категории, например.

class Category < ActiveRecord::Base
  def transaction_amount
    transactions.sum("amount_cents")
  end
end

<% categories.each do |c| %>
  ....
    <%= c.transaction_amount %>
  ....
<% end %>

Технически говоря, расчет по-прежнему выполняется при рендеринге представления, но логика того, как рассчитывается эта суммированная сумма, больше не находится внутри самого представления. Теперь все соображения обращают внимание на то, что он может отправить сообщение transaction_amount объектам категории. Это также оставляет вам место для добавления кеша для сумм или для прекращения передачи фактических записей, но вместо этого передавайте статические объекты (которые не являются моделями ActiveRecord), которые выходят из некоторого фрагмента кода, который выполняет сумму в более эффективным способом.