Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Rails how do I use find_each method with index?

I can use Rails find_each method like :

User.find_each(:batch_size => 10000) do |user|
  ------
end 

With find_each method is there any way to get the index of the array ? like :

User.find_each(:batch_size => 10000).with_index do |user, index|
  ------
end 
like image 748
Abhi Avatar asked Dec 27 '13 09:12

Abhi


3 Answers

As an update to this question. Active Record 4.1.4 has added support for find_each.with_index as pointed in the documentation.

User.find_each(:batch_size => 1000).with_index do |user, index|
  user.call_method(index)
end
like image 186
Ron Avatar answered Oct 19 '22 18:10

Ron


Update: As of Rails 4.1.4 this is possible. See this answer for more. Example:

User.find_each(:batch_size => 1000).with_index do |user, index|
  user.call_method(index)
end

As you can see from the method definition, this is not possible.

def find_each(options = {})
  find_in_batches(options) do |records|
    records.each { |record| yield record }
  end
end

In order to accomplish what you want to do, you need to either create your own modified version of the method

class User
  def find_each(options = {})
    find_in_batches(options) do |records|
      records.each_with_index { |record| yield record, index }
    end
  end
end

User.find_each(:batch_size => 10000) do |user, index|
  ------
end 

or use an instance variable.

index = 0
User.find_each(:batch_size => 10000) do |user|
  # ...
  index += 1
end 

There is no other default solution as shown by the method implementation.

like image 31
Simone Carletti Avatar answered Oct 19 '22 19:10

Simone Carletti


Your question is already implemented in the Rails master branch. To get this, it requires using Rails edge, as this has not been merged into any release as of yet. See this merged pull request: https://github.com/rails/rails/pull/10992.

So add this to your Gemfile:

gem 'rails', github: 'rails/rails'

This will allow you to run the code you described:

User.find_each(batch_size: 10000).with_index do |user, index|
  puts "UserID: #{user.id.to_s} has index ##{index.to_s}"
end

Granted, running on the edge release is risky, so don't do this in production. But look at the pull request to see the small amount of code added to get this working. You can monkey patch until it is merged into a Rails release.

like image 12
Martin Bjeldbak Madsen Avatar answered Oct 19 '22 20:10

Martin Bjeldbak Madsen