Q:

ruby method with for loop, unexpected return

I have a model MyModel with a method to return a specific record (see logic below).
def self.find_future_rec   #note2
  rec = find(rand(MyModel.count)+1)   #note1
  while rec.nil? | (rec.expdate<Date.today)
    rec = find(rand(MyModel.count)+1)
  end
  return rec
end

Every record of MyModel class has a variable expdate of Date class. (I know this is a horrible way to find a record, this is more for my own edification and also some test code.)

This method will iterate through several undesirable records before finding an appropriate record, but the record returned is always the one found at note 1, the first record queried. Is there some lazy assignment thing going on here?
I had to add self at note2 to be able to call the method in a static context. Is this the correct interpretation?

A:

The find method never returns nil when you give it a single ID to find: if it can't find the record you're asking for, it raises an ActiveRecord::RecordNotFound exception. So, rec is always non-nil and rec.nil? is always false. That means that your loop is really like this:
while rec.expdate < Date.today

If your loop is always returning the rec from #note1 then you're never entering the while loop at all and you're always getting a desirable MyModel on the first try.
Other points to consider:

Sometimes things get deleted so Model.count + 1 is not necessarily the maximum ID.
find raises an exception to indicate failure so you need to rescue ActiveRecord::RecordNotFound rather than check for nil.

