Trivial Rails Question, I am unable to explain the behavior

20 views
Skip to first unread message

Ankur Jain

unread,
Apr 19, 2012, 5:03:05 PM4/19/12
to rubyonra...@googlegroups.com
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.

Tyler

unread,
Apr 19, 2012, 10:08:10 PM4/19/12
to rubyonra...@googlegroups.com
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

Dheeraj Kumar

unread,
Apr 19, 2012, 10:14:51 PM4/19/12
to rubyonra...@googlegroups.com
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]).count > 0})




Dheeraj Kumar

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/iP-o3etIsskJ.
To post to this group, send email to rubyonra...@googlegroups.com.
To unsubscribe from this group, send email to rubyonrails-ta...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.

Matt Jones

unread,
Apr 20, 2012, 10:22:01 AM4/20/12
to rubyonra...@googlegroups.com


On Thursday, 19 April 2012 22:14:51 UTC-4, Dheeraj Kumar wrote:
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]).count > 0})



Um, no. That won't even parse.
 
 
On Friday 20 April 2012 at 7:38 AM, Tyler wrote:
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


On Thursday, April 19, 2012 2:03:05 PM UTC-7, Ankur Jain wrote:
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}


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 Jones

Ankur Jain

unread,
Apr 20, 2012, 10:54:13 AM4/20/12
to rubyonra...@googlegroups.com

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.
 

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/gr_Z8phcivsJ.

Matt Jones

unread,
Apr 21, 2012, 10:30:02 AM4/21/12
to rubyonra...@googlegroups.com


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

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}


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 Jones


 
Reply all
Reply to author
Forward
0 new messages