Shift is your friend
crops.each do |c| c.calculate_status(user) end
takes 0.3 seconds to run. This code:
crops = crops.to_a while(c = crops.shift) c.calculate_status(user) end
takes 0.00001 seconds to run. Using shift lets Ruby clear that junk out of memory as soon as you leave the current iteration of your while loop. Each makes you keep it around.