If you’ve been making web apps with Rails for long enough, you will have encountered ActiveRecord’s handy find_each method. It iterates over a bunch of records, loading only 1000 at a time, which allows you to avoid running out of memory. Pretty handy if you need to do something to all 1 million of your User records!
When you use find_each, you probably just pass it a block like so:
That’s well and good if you want to do something to each user. But what if you need to find that one particular user out of a million that fails validation? That’s not something the DB can easily query.
Did you know that find_each can be called without a block? If you do that, it instead return an enumerable, which then allows you to call any of the typical Ruby array methods you’re used to. For example, if you want to find all invalid users:
Depending on your situation, that may return way too many users. What if you just want the earliest invalid user?
Hold on, isn’t find used for looking up records by their primary key? Not in this case. Since find_each returns an Enumerable (not an ActiveRecord Class), this is Ruby’s find, not ActiveRecord’s find. It iterates over each object passed to it and return the first to result in true from the block.
You can use any of the Enumerable methods, including any?, reduce, or count. I recommend avoiding methods like map and sort since you end up loading all the records into memory, which is probably what you wanted to avoid by using find_each.
Bonus: When using find_each you can first filter out records using where, but you cannot order them using order, nor can you use limit. Those will just silently not work! As always, read the documentation… carefully.