user2246674 is correct, the if statement is returning nil, but inject should always return acc
You can use a turnery operator to make this easy
dfs = p.disk_items.inject(0) { |acc, di| di.type == "DiskFile" ? acc + 1 : acc }
Question
I'm expecting 9
, but getting nil
. Not sure why.
> dfs = p.disk_items.inject { |acc, di| acc + 1 if di.type == "DiskFile" }
=> nil
The same problem:
> dfs = p.disk_items.inject(0) { |acc, di| if di.type == "DiskFile" then acc + 1 end }
=> nil
Clearly there are nine occurrences where di.type == "DiskFile"
is true:
> dfs = p.disk_items.inject(0) { |acc, di| puts di.type == "DiskFile" }
true
true
true
true
true
true
true
true
true
false
=> nil
What am I screwing up? If I can't use conditionals, then maybe there's a better way to count all the ActiveRecord
objects in an array that satisfies a condition on an attribute.
Edit: FWIW:
> p.disk_items.class
=> ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_DiskItem
looks like this implementation in Rails source of count
may not accept blocks? Though I may be reading this wrong or looking in the wrong place...
Solution
user2246674 is correct, the if statement is returning nil, but inject should always return acc
You can use a turnery operator to make this easy
dfs = p.disk_items.inject(0) { |acc, di| di.type == "DiskFile" ? acc + 1 : acc }
OTHER TIPS
When the if
"doesn't run" the block evalutates to nil
. This happens on the last case and the result (nil
) is returned.
Consider (the long-hand):
if di.type == "DiskFile" then
acc + 1
else
acc # so we never return nil
end
While there are various short-hands (i.e. ?:), I would use a count {block}
. If needing to do something else with the values (perhaps still using in an inject "sometimes"), select
might also be useful.
p.disk_items.count {|di| di.type == "DiskFile"}