1

In a Rails index view you iterate the collection and per item in the collection data is presented. In most cases I end up with a complex view, because there is a need to do additional calculations for a specific item in the collection. Here is a typical example:

- if @projects.blank?
  = render "shared/placeholder", colspan: "10"
- else
  - @hours_total = 0
  - @turnover_total = 0
  - @projectusers_total = 0
  - @projects.each do |project|
    - decorate project do |decorates|
      - project_calc = ProjectCalculator.new(project)
      - hours = project_calc.get_project_data("hours")
      - turnover = project_calc.get_project_data("turnover")
      - @hours_total += hours
      - @turnover_total += turnover
      - @projectusers_total += project.projectusers.size
      %tr
        %td= link_to decorates.data_field(project.name), admin_project_path(project)
        %td= decorates.data_field(project.customer.name) unless project.customer.blank?
        %td= decorates.data_field(project.company.name_short)
        %td= decorates.status
        %td= decorates.data_field(project.projectusers.size)
        %td= decorates.decimal(hours)
        %td= decorates.amount(turnover)
        %td= decorates.fixed_price
        %td= decorates.show_progress("hours", "compact", hours)
        %td= decorates.show_progress("turnover", "compact", turnover)

An improvement I already implemented is to use a decorator for view specific stuff and another one is to use service objects for the actual calculations.

But what bothers me here are all the calculations. What is a solution to make this simpler and ideally not having this in the view?

John
  • 6,404
  • 14
  • 54
  • 106

1 Answers1

1

What about using a Presenter?

This link helped me a lot: http://robertomurray.co.uk/blog/2014/decorators-presenters-delegators-rails/

Here is another Short overview

In your case you could implement it like this

# app/presenter/project_presenter.rb
class ProjectPresenter
  attr_accessor :project, :project_calculator

  def initialize project
    @project = project
    @project_calculator = ProjectCalculator.new
  end

  def hours
    project_calculator.get_project_data("hours")
  end

  def show_progress *args
    # calculate progress
  end
end

In your controller you can initialize the presenter for every project

  @projects = Project.all.collect { |project| ProjectPresenter.new(project) }

So, your view can access the presenter with

  - @projects.each do |project|
    %tr
      %td= project.show_progress('hours')

Hope it will help

ciao boris

rider_on_rails
  • 1,987
  • 1
  • 13
  • 9
  • Thanks, this helps a lot. A presenter is just another name for a decorator, right? – John Nov 07 '14 at 18:06
  • you´re welcome :-) http://stackoverflow.com/questions/7860301/rails-patterns-decorator-vs-presenter gives you a good overview over both. Generally spoken: you use a presenter to form a bridge between 'Model and View' while a decorator adds more functionality for a model. – rider_on_rails Nov 08 '14 at 16:01