views:

140

answers:

2

I am collecting the values for a specific column from a named_scope as follows:

a = survey_job.survey_responses.collect(&:base_pay)

This gives me a numeric array for example (1,2,3,4,5). I can then pass this array into various functions I have created to retrieve the mean, median, standard deviation of the number set. This all works fine however I now need to start combining multiple columns of data to carry out the same types of calculation.

I need to collect the details of perhaps three fields as follows:

survey_job.survey_responses.collect(&:base_pay)
survey_job.survey_responses.collect(&:bonus_pay)
survey_job.survey_responses.collect(&:overtime_pay)

This will give me 3 arrays. I then need to combine these into a single array by adding each of the matching values together - i.e. add the first result from each array, the second result from each array and so on so I have an array of the totals.

How do I create a method which will collect all of this data together and how do I call it from the view template?

Really appreciate any help on this one...

Thanks

Simon

A: 

Here's a method that will combine an arbitrary number of arrays by taking the sum at each index. It'll allow each array to be of different length, too.

def combine(*arrays)
  # Get the length of the largest array, that'll be the number of iterations needed
  maxlen = arrays.map(&:length).max
  out = []

  maxlen.times do |i|
    # Push the sum of all array elements at a given index to the result array
    out.push( arrays.map{|a| a[i]}.inject(0) { |memo, value| memo += value.to_i } )
  end

  out
end

Then, in the controller, you could do

base_pay = survey_job.survey_responses.collect(&:base_pay)
bonus_pay = survey_job.survey_responses.collect(&:bonus_pay)
overtime_pay = survey_job.survey_responses.collect(&:overtime_pay)

@total_pay = combine(base_pay, bonus_pay, overtime_pay)

And then refer to @total_pay as needed in your view.

Daniel Vandersluis
I'm doing this calculation inside the main loop for the report. I loop through survey_jobs and need to do this set of calculations for each survey_job in the collection. If I post the controller code I get an error: NameError in Admin/surveysController#show undefined local variable or method `survey_job' for #<SurveysController:0x2230ad0>Am I misunderstanding how I should apply this code in the controller?
+1  A: 
s = survey_job.survey_responses
pay = s.collect(&:base_pay).zip(s.collect(&:bonus_pay), s.collect(&:overtime_pay))
pay.map{|i| i.compact.inject(&:+) }

Do that, but with meaningful variable names and I think it will work.

Define a normal method in app/helpers/_helper.rb and it will work in the view

Edit: now it works if they contain nil or are of different sizes (as long as the longest array is the one on which zip is called.

Ben Hughes
Note that this method will not work if your arrays are not all the same size or if they contain nil.
Daniel Vandersluis
How do I call this from the view?
define it as a method in the helper that corresponds to your current controller (located in app/helpers) and it will be available to you in your view. if you define it in app/helpers/application_helper.rb it will be available in all views.
Ben Hughes
I added it in application_helper.rb but I can't work out how to reference it from the view.I tried <%= total_cash_pay %> but I guess that's not correct as I get an error: undefined local variable or method `survey_job' for #<ActionView::Base:0x27dc650>
functions can take parameters...
Ben Hughes