I have a Rails app that contains a TeamSeason model class. This class has a has_one association with a Team model class, and a has_many association to another TeamSeason called opponents. I’m now trying to write a method that passes in a Team and determines whether any of its opponents are associated with that Team. The method I wrote looks something like this:
def plays?(against_team)
total = opponents.count {|opponent| opponent.team == against_team}
return (total > 0)
end
The count method should count the number of array elements that yield a true value with the block I specified. However, it appears that it is always returning the full length of the array. It’s as if the block I specified always yields a true value, no matter what.
I added various puts calls to try and figure out where my logic is going wrong. Here’s my observations:
-
When I add any
putscalls inside the block next to the count method, I do not see any output for those statements. It appears that the contents of the block are never being executed -
When I insert an additional loop using the opponents array’s
eachmethod and a block, I can print the value of my array objects and confirm they are evaluate as I expect. I can evenputsthe value ofopponent.team == against_teamand verify that the block I wrote evaluates tofalsesome of the time, as it should.
What am I missing here?
opponentsis not a standard ruby Array – it’s an ActiveRecord association proxy and behaves differently for certain methods.countwill query the database for the number of opponents, and the block you are passing will not be evaluated. A simpler way to do what you want is like so:This will ask the database what you want, and avoid loading all opponents when you are only checking for a specific match. Alternatively, you can load the entire opponents list and use
any?:Note that this will not only load all opponents, but it will load each opponent’s team one at a time – resulting in an N+1 query (which leads to performance issues). You can avoid this by eager loading the associated team using
includes():