diff options
author | Sina Siadat <siadat@gmail.com> | 2015-07-18 20:44:13 +0430 |
---|---|---|
committer | Sina Siadat <siadat@gmail.com> | 2015-08-07 10:26:38 +0430 |
commit | 25cee1f0373aa3b1d893413a959375480e0ac684 (patch) | |
tree | afb44866a3b5f9411b02f6c91aa9c572e5beeafe /activerecord/lib/active_record/relation/batches | |
parent | 4b91db5b125dd7bd735e7f42eb8e2c14c0e6757e (diff) | |
download | rails-25cee1f0373aa3b1d893413a959375480e0ac684.tar.gz rails-25cee1f0373aa3b1d893413a959375480e0ac684.tar.bz2 rails-25cee1f0373aa3b1d893413a959375480e0ac684.zip |
Add ActiveRecord::Relation#in_batches
`in_batches` yields Relation objects if a block is given, otherwise it
returns an instance of `BatchEnumerator`. The existing `find_each` and
`find_in_batches` methods work with batches of records. The new API
allows working with relation batches as well.
Examples:
Person.in_batches.each_record(&:party_all_night!)
Person.in_batches.update_all(awesome: true)
Person.in_batches.delete_all
Person.in_batches.map do |relation|
relation.delete_all
sleep 10 # Throttles the delete queries
end
Diffstat (limited to 'activerecord/lib/active_record/relation/batches')
-rw-r--r-- | activerecord/lib/active_record/relation/batches/batch_enumerator.rb | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/relation/batches/batch_enumerator.rb b/activerecord/lib/active_record/relation/batches/batch_enumerator.rb new file mode 100644 index 0000000000..153aae9584 --- /dev/null +++ b/activerecord/lib/active_record/relation/batches/batch_enumerator.rb @@ -0,0 +1,67 @@ +module ActiveRecord + module Batches + class BatchEnumerator + include Enumerable + + def initialize(of: 1000, begin_at: nil, end_at: nil, relation:) #:nodoc: + @of = of + @relation = relation + @begin_at = begin_at + @end_at = end_at + end + + # Looping through a collection of records from the database (using the + # +all+ method, for example) is very inefficient since it will try to + # instantiate all the objects at once. + # + # In that case, batch processing methods allow you to work with the + # records in batches, thereby greatly reducing memory consumption. + # + # Person.in_batches.each_record do |person| + # person.do_awesome_stuff + # end + # + # Person.where("age > 21").in_batches(of: 10).each_record do |person| + # person.party_all_night! + # end + # + # If you do not provide a block to #each_record, it will return an Enumerator + # for chaining with other methods: + # + # Person.in_batches.each_record.with_index do |person, index| + # person.award_trophy(index + 1) + # end + def each_record + return to_enum(:each_record) unless block_given? + + @relation.to_enum(:in_batches, of: @of, begin_at: @begin_at, end_at: @end_at, load: true).each do |relation| + relation.to_a.each { |record| yield record } + end + end + + # Delegates #delete_all, #update_all, #destroy_all methods to each batch. + # + # People.in_batches.delete_all + # People.in_batches.destroy_all('age < 10') + # People.in_batches.update_all('age = age + 1') + [:delete_all, :update_all, :destroy_all].each do |method| + define_method(method) do |*args, &block| + @relation.to_enum(:in_batches, of: @of, begin_at: @begin_at, end_at: @end_at, load: false).each do |relation| + relation.send(method, *args, &block) + end + end + end + + # Yields an ActiveRecord::Relation object for each batch of records. + # + # Person.in_batches.each do |relation| + # relation.update_all(awesome: true) + # end + def each + enum = @relation.to_enum(:in_batches, of: @of, begin_at: @begin_at, end_at: @end_at, load: false) + return enum.each { |relation| yield relation } if block_given? + enum + end + end + end +end |