Reputation: 601
I'm using this code in my controller to access the average paper_weight
for all my users in the Heavy
classification.
if User.where(industry_type: 'Heavy')
.joins(:papers)
.where(papers: { paper_type: 'Officepaper' } )
.pluck('avg(paper_weight)').first.nil?
@heavy_indust_officepaper == 0
else
@heavy_indust_officepaper = User.where(industry_type: 'Heavy')
.joins(:papers)
.where(papers: { paper_type: 'Officepaper' } )
.pluck('avg(paper_weight)').first * 3
end
Then the variable @heavy_indust_officepaper
is displayed in a view.
The problem is that this code above doesn't seem to be calculating the average correctly when one or more users have a nil
entry in paper_type: 'Officepaper'
.
I know that because I have two users in the industry_type: 'Heavy'
One of them has one entry of paper_type: 'Officepaper'
which is the decimal 30.
And the other user has nil
entry in paper_type: 'Officepaper'
.
By my understanding the calculation should be 30 + 0 / 2(users) = 15
and then the 15
is multiplied by 3
which should give 45
But instead the variable @heavy_indust_officepaper
is displaying 90
in the view... which must be the result of 30 * 3
Is there a way to convert the nil
to 0
with in the code above???
Please Can some one advise me?
Here is a link to a question I asked earlier to day, I got help with this code from it Using .average with .pluck in ruby on rails app?
Upvotes: 3
Views: 2782
Reputation: 52357
The issue here is (among others) is your misunderstanding of what pluck
does. It returns you an array of average someting for every user. So in your example it returns you
[30, nil]
That's why you get 90
([30, nil].first * 30
=> 90
).
To get average for all users, use average
.
Solution:
You can use COALESCE
to convert NULL
to zero while calculating average:
User.where(industry_type: 'Heavy')
.joins(:papers)
.where(papers: { paper_type: ['Officepaper', nil] } )
.average('COALESCE(papers.paper_weight, 0)') * 3
#=> 15
One thing to be aware of is that while COALESCE
will convert any null
value to 0
while calculating, average
will still return nil
if there were no records to calculate average
on.
How to handling this case is for you to decide, but @max already has shown one of the pretty straightforward options (assuming that above query results is written to average
variable):
average.nil? ? 0 : average * 3
Upvotes: 5
Reputation: 101901
avg = User.where(industry_type: 'Heavy')
.joins(:papers)
.where(papers: { paper_type: ['Officepaper', nil] } )
.average('papers.paper_weight')
@heavy_indust_officepaper = avg.nil? ? 0 : avg * 3
Upvotes: 1