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...

Was it helpful?

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"}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top