views:

196

answers:

2

This is the code in my reports controller, it just looks so bad, can anyone give me some suggestions on how to tidy it up?

# app\controller\reports_controller.rb

 @report_lines  = []
   @sum_wp, @sum_projcted_wp, @sum_il, @sum_projcted_il, @sum_li,@sum_gross_profit ,@sum_opportunities = [0,0,0,0,0,0,0]    
 date = @start_date

 num_of_months.times do
    wp,projected_wp, invoice_line,projected_il,line_item, opp = Report.data_of_invoicing_and_delivery_report(@part_or_service,date)
    @sum_wp += wp
    @sum_projcted_wp +=projected_wp
    @sum_il=invoice_line
    @sum_projcted_il +=projected_il
    @sum_li += line_item
    gross_profit = invoice_line - line_item
    @sum_gross_profit += gross_profit
    @sum_opportunities += opp
    @report_lines << [date.strftime("%m/%Y"),wp,projected_wp ,invoice_line,projected_il,line_item,gross_profit,opp]
    date = date.next_month
 end

I'm looking to use some method like

@sum_a,@sum_b,@sum_c += [1,2,3]
+2  A: 

Create a summation object that contains all those fields, pass the entire array to @sum.increment_sums(Report.data_of...)

Kevin Peterson
+4  A: 

My instant thought is: move the code to a model.

The objective should be "Thin Controllers", so they should not contain business logic.

Second, I like to present my report lines to my Views as OpenStruct() objects, which seems cleaner to me.

So I'd consider moving this accumulation logic into (most likely) a class method on Report and returning an array of "report line" OpenStructs and a single totals OpenStruct to pass to my View.

My controller code would become something like this:

@report_lines, @report_totals = Report.summarised_data_of_inv_and_dlvry_rpt(@part_or_service, @start_date, num_of_months)

EDIT: (A day later)

Looking at that adding accumulating-into-an-array thing, I came up with this:

require 'test/unit'

class Array
  def add_corresponding(other)
    each_index { |i| self[i] += other[i] }
  end
end

class TestProblem < Test::Unit::TestCase
  def test_add_corresponding
    a = [1,2,3,4,5]
    assert_equal [3,5,8,11,16], a.add_corresponding([2,3,5,7,11])
    assert_equal [2,3,6,8,10], a.add_corresponding([-1,-2,-2,-3,-6])
  end
end

Look: a test! It seems to work OK. There are no checks for differences in size between the two arrays, so there's lots of ways it could go wrong, but the concept seems sound enough. I'm considering trying something similar that would let me take an ActiveRecord resultset and accumulate it into an OpenStruct, which is what I tend to use in my reports...

Our new Array method might reduce the original code to something like this:

totals = [0,0,0,0,0,0,0]    
date = @start_date

num_of_months.times do
  wp, projected_wp, invoice_line, projected_il, line_item, opp = Report.data_of_invoicing_and_delivery_report(@part_or_service,date)
  totals.add_corresponding [wp, projected_wp, invoice_line, projected_il, line_item, opp, invoice_line - line_item]
  @report_lines << [date.strftime("%m/%Y"),wp,projected_wp ,invoice_line,projected_il,line_item,gross_profit,opp]
  date = date.next_month
end

@sum_wp, @sum_projcted_wp, @sum_il, @sum_projcted_il, @sum_li, @sum_opportunities, @sum_gross_profit = totals

...which if Report#data_of_invoicing_and_delivery_report could also calculate gross_profit would reduce even further to:

num_of_months.times do
  totals.add_corresponding(Report.data_of_invoicing_and_delivery_report(@part_or_service,date))
end

Completely un-tested, but that's a hell of a reduction for the addition of a one-line method to Array and performing a single extra subtraction in a model.

Mike Woodhouse
Thanks for the tips, however I'm looking to use some methods like@sum_a,@sum_b,@sum_c += [1,2,3]Any idea about this ?
Shuoling Liu