I have an app where I retrieve a list of users from a specific country.
I did this in the UsersController:
@fromcanada = User.find(:all, :conditions => { :country => 'canada' })
and then turned it into a scope on the User model
scope :canada, where(:country => 'Canada').order('created_at DESC')
but I also want to be able to retrieve a random person or multiple persons from the country. I found this method that’s supposed to be an efficient way to retrieve a random user from the database.
module ActiveRecord
class Base
def self.random
if (c = count) != 0
find(:first, :offset =>rand(c))
end
end
end
end
However, I have a few questions about how to add it, and how the syntax works.
-
Where would I put that code? Direct in the
Usermodel? -
Syntax: so that I don’t use code that I don’t understand, can you explain how the syntax is working? I don’t get (
c = count). What iscountcounting? What isrand(c)doing? Is it finding the first one starting at the offset? Ifrandis an expensive method (hence the need to create a different more efficientrandommethod), why use the expensive ‘rand‘ in this new more efficientrandommethod? -
How could I add the call to
randomon myfindmethod in theUsersController? How to add it to the scope in the model? -
Building on question 3, is there a way to get two or three random users?
I wouldn’t monkey patch that (or anything else!) into ActiveRecord, putting that into your User would make more sense.
The
countis counting how many elements there are in your table and storing that number inc. Thenrand(c)gives you a random integer in the interval[0,c)(i.e.0 <= rand(c) < c). The:offsetworks the way you think it does.randisn’t terribly expensive but doingorder by random()inside the database can be very expensive. Therandommethod that you’re looking at is just a convenient way to get a random record/object from the database.Adding it to your own User would look something like this:
That would allow you to chain
randomafter a bunch of scopes:but the result of
randomwould be a single user so your chaining would stop there.If you wanted multiple users you’d want to call
randommultiple times until you got the number of users you wanted. You could try this:to get three random users but the users would be clustered together in whatever order the database ended up with after your other scopes and that’s probably not what you’re after. If you want three you’d be better off with something like this:
You’d just grab a random user, update your scope chain to exclude them, and repeat until you’re done. You would, of course, want to make sure you had three users first.
You might want to move the ordering out of your
canadascope: one scope, one task.