Trivial Rails Question, I am unable to explain the behavior

Following 2 statements look identical to me, however the first one
returns
only one object but the second one returns correctly an array of 4
objects.

What is happening here is simple, I get all the Grade objects (1st one
using Grade.find(:all) and second one using Grade.all), and then filter
out
all the grade objects where they have worksheets assigned to them.

@grades = Grade.find(:all){|grade| Worksheet.find(:all,:conditions=>
[‘grade_id =?’,grade.id]).count > 0}

*
*
@grades = Grade.all {|grade| Worksheet.find(:all,:conditions=>
[‘grade_id =?’,grade.id]).count > 0}

Can somebody explain why the results would be different for these 2
statements.

I don’t have rails in front of me, but looks like there may be a problem
with implied parentheses. Have you tried things like:
@grades = Grade.all() {|grade| Worksheet.find(:all,:conditions=>
[‘grade_id =?’,grade.id]).count > 0}
*
*

Again I can’t test so not sure if that helps

The find method takes the option hash as the last parameter. Either use
Model.all(options) or Model.find(:all, options)

The correct code is:

@grades = Grade.find(:all, {|grade| Worksheet.find(:all,:conditions=>
[‘grade_id =?’,grade.id (http://grade.id)]).count > 0})

Dheeraj K.

Thanks Matt, Your alternative method on how to best get the data
definitely
is a much optimized solution then what I was using, I am not using that
and
everything works great.

However, I am still confused on one part.

as per my understanding

Grade.find(:all)

and

*Grade.all *

both should return an array of Grade objects, so how are the results
different if I just pass the objects through this block.
{|grade| Worksheet.find(:all,:conditions=> [‘grade_id
=?’,grade.id]).count

0}

Thanks again for the help.

On Thursday, 19 April 2012 22:14:51 UTC-4, Dheeraj K. wrote:

Um, no. That won’t even parse.

@grades = Grade.find(:all){|grade| Worksheet.find(:all,:conditions=>
[‘grade_id =?’,grade.id]).count > 0}

*
*
@grades = Grade.all {|grade| Worksheet.find(:all,:conditions=>
[‘grade_id =?’,grade.id]).count > 0}

There are two things going on here:

  • in the first statement, find(:all) acts like Enumerable#find when
    passed
    a block. Each of the found objects is passed to the block and the first
    one
    that returns a truthy value is returned.

  • in the second statement, all doesn’t call the block so you get exactly
    the same results you would have without a block at all.

If this is an operation you do a lot in your app, you may want to check
out
the :counter_cache option of belongs_to, which will allow you to write
this
(correctly) as:

@grades = Grade.where(‘worksheets_count > 0’).all

Also note that if counts are all you’re looking for, you should avoid
doing
a find(:all) on them (as on Worksheet above); the count method on the
model
class can do this much more efficiently (with a SQL COUNT statement,
rather
than loading a bunch of objects and then counting them).

–Matt J.

On Friday, 20 April 2012 10:54:13 UTC-4, Ankur Jain wrote:

Grade.find(:all)

A block by itself doesn’t do ANYTHING - it’s entirely dependent on the
function it’s passed to. For instance:

def hello(who)
puts “Hello #{who}”
end

hello(‘World’) # prints “Hello World”
hello(‘World’) { |x| puts ‘WAT’ } # prints “Hello World” - doesn’t do
anything with the block

The case you encountered with find(:all) was specifically coded to use
the
block just like Enumerable#find:

a = [1,2,3,4]

a.find { |x| x > 2 } # => returns 3, the first value in the array that
the
block returns a truthy value for

–Matt J.