From 761bc751d31c22e2c2fdae2b4cdd435b68b6d783 Mon Sep 17 00:00:00 2001 From: Toshiyuki Kawanishi Date: Sat, 15 Sep 2012 17:39:11 +0900 Subject: Fix find_in_batches with customized primary_key --- activerecord/CHANGELOG.md | 15 +++++++++++++++ activerecord/lib/active_record/relation/batches.rb | 13 +++++++------ activerecord/test/cases/batches_test.rb | 11 +++++++++++ activerecord/test/models/post.rb | 5 +++++ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 8c99a3929e..71dc960309 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,20 @@ ## Rails 4.0.0 (unreleased) ## +* Fix `find_in_batches` when primary_key is set other than id. + You can now use this method with the primary key which is not integer-based. + + Example: + + class Post < ActiveRecord::Base + self.primary_key = :title + end + + Post.find_in_batches(:start => 'My First Post') do |batch| + batch.each { |post| post.author.greeting } + end + + *Toshiyuki Kawanishi* + * You can now override the generated accessor methods for stored attributes and reuse the original behavior with `read_store_attribute` and `write_store_attribute`, which are counterparts to `read_attribute` and `write_attribute`. diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index 4d14506965..d32048cce1 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -36,12 +36,12 @@ module ActiveRecord # want multiple workers dealing with the same processing queue. You can # make worker 1 handle all the records between id 0 and 10,000 and # worker 2 handle from 10,000 and beyond (by setting the +:start+ - # option on that worker). + # option on that worker). You can also use non-integer-based primary keys + # if start point is set. # # It's not possible to set the order. That is automatically set to - # ascending on the primary key ("id ASC") to make the batch ordering - # work. This also mean that this method only works with integer-based - # primary keys. You can't set the limit either, that's used to control + # ascending on the primary key (e.g. "id ASC") to make the batch ordering + # work. You can't set the limit either, that's used to control # the batch sizes. # # Person.where("age > 21").find_in_batches do |group| @@ -62,7 +62,8 @@ module ActiveRecord ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size") end - start = options.delete(:start).to_i + start = options.delete(:start) + start ||= 0 batch_size = options.delete(:batch_size) || 1000 relation = relation.reorder(batch_order).limit(batch_size) @@ -70,7 +71,7 @@ module ActiveRecord while records.any? records_size = records.size - primary_key_offset = records.last.id + primary_key_offset = records.last.send(primary_key) yield records diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index cdd4b49042..3b4ff83725 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -124,4 +124,15 @@ class EachTest < ActiveRecord::TestCase assert_equal special_posts_ids, posts.map(&:id) end + def test_find_in_batches_should_use_any_column_as_primary_key + title_order_posts = Post.order('title asc') + start_title = title_order_posts.first.title + + posts = [] + PostWithTitlePrimaryKey.find_in_batches(:batch_size => 1, :start => start_title) do |batch| + posts.concat(batch) + end + + assert_equal title_order_posts.map(&:id), posts.map(&:id) + end end diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index c995f59a15..9858f68c4a 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -186,3 +186,8 @@ class SpecialPostWithDefaultScope < ActiveRecord::Base self.table_name = 'posts' default_scope { where(:id => [1, 5,6]) } end + +class PostWithTitlePrimaryKey < ActiveRecord::Base + self.table_name = 'posts' + self.primary_key = :title +end -- cgit v1.2.3