54

Now that ActiveRecord::Relation#all is deprecated in Rails 4, how do I iterate over all records?

Previously:

Foo.all.each do |foo|
  # whatever
end

I can approximate it now like this, but it feels dirty:

Foo.where(true).each do |foo|
  # whatever
end

Is there a better way?

Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
jemminger
  • 5,133
  • 4
  • 26
  • 47

4 Answers4

75

According to the Rails Guide on Active Record Query Interface, the correct way to iterate through all records is by using find_each.

Using Foo.all.each will load the entire table into memory, instantiating all the rows; then iterate through the instances. find_each does this in batches, which is more efficient in terms of memory usage.

From the guide:

The find_each method retrieves a batch of records and then yields each record to the block individually as a model. In the following example, find_each will retrieve 1000 records (the current default for both find_each and find_in_batches) and then yield each record individually to the block as a model. This process is repeated until all of the records have been processed:

User.find_each do |user|
  NewsLetter.weekly_deliver(user)
end

References:

18

yes, Foo.all.

all is deprecated on an ActiveRecord::Relation (eg. Foo.where(true)), not on ActiveRecord::Base.

http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html#method-i-all

sevenseacat
  • 24,699
  • 6
  • 63
  • 88
  • Aha, I guess the deprecation warnings are getting it wrong then. I'm being warned wherever I'm using Foo.all – jemminger Aug 11 '13 at 18:50
  • you may have to elaborate more on the code you're using and the warning you're getting, then. – sevenseacat Aug 12 '13 at 01:14
  • It appears that "they" set where(true) so it now crashes in later Rails4.x versions. Error: "RuntimeError: unsupported: TrueClass". Why let something work for others, if it annoys your sensibilities? Just force it down everyone's throat and let them loose hundreds of their life-hours searching for the problems you created for them on purpose. – JosephK Jul 08 '16 at 08:29
13

Release notes for Rails 4:

Model.all now returns an ActiveRecord::Relation, rather than an array of records. Use Relation#to_a if you really want an array.

So your code will look like this:

Foo.all.to_a.each do |foo|
  # whatever
end

See http://guides.rubyonrails.org/4_0_release_notes.html#active-record

user3356885
  • 391
  • 2
  • 6
0

This appears to be an incorrect deprecation warning somewhere in Rails. As of Rails 4.0.2 the warning message still exists. I get the following error when I try and run Foo.all:

DEPRECATION WARNING: Relation#all is deprecated. If you want to eager-load a relation, you can call #load (e.g. Post.where(published: true).load). If you want to get an array of records from a relation, you can call #to_a (e.g. Post.where(published: true).to_a).

I'm almost 100% certain I watched in a RailsCasts that #all was being changed to return an Relation in Rails 4 (instead of an array) - no mention of deprecation.

WebDev
  • 1,097
  • 8
  • 6