В Rails как использовать метод find_each с индексом?

Я могу использовать метод Rails find_each, например:

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

С методом find_each есть ли способ получить индекс массива? как:

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

Ответ 1

Как видно из определения метода, это невозможно.

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

Чтобы выполнить то, что вы хотите сделать, вам нужно либо создать свою собственную модифицированную версию метода

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 

или используйте переменную экземпляра.

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

Нет другого решения по умолчанию, как показано в реализации метода.

Ответ 2

Как обновление этого вопроса. Active Record 4.1.4 добавила поддержку find_each.with_index как указано в документации.

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

Ответ 3

Ваш вопрос уже реализован в главной ветке Rails. Чтобы получить это, для этого требуется использовать Rails edge, так как это еще не слилось ни с одной версией. См. Этот запрос с объединенным тягой: https://github.com/rails/rails/pull/10992.

Поэтому добавьте это в свой Gemfile:

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

Это позволит вам запустить код, который вы описали:

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

Разумеется, работа на выпуске края опасна, поэтому не делайте этого в процессе производства. Но посмотрите на запрос на pull, чтобы увидеть небольшое количество добавленного кода, чтобы заставить это работать. Вы можете патч обезьяны, пока он не будет объединен в релиз Rails.

Ответ 4

Просто используйте локальную переменную:

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

Ответ 5

Вы можете получить всех пользователей и отправить их через блок вместе со своим соответствующим индексом следующим образом.

User.all.each_with_index do |user, index|
  puts "email is " + "#{user.email}" + " and user index is " + "#{index}"
end