it has a bug or feature in it. yeilding inside with_scope will put scope on the same class
migration
class CreatePeople < ActiveRecord::Migration
def self.up
create_table :people do |t|
t.string :name
t.integer :mama_id, :papa_id, :age
t.timestamps
end
end
def self.down
drop_table :people
end
end
model
class Person < ActiveRecord::Base has_one :mama, :class_name => 'Person', :foreign_key => 'mama_id' has_one :papa, :class_name => 'Person', :foreign_key => 'papa_id' end
test
class PersonTest < ActiveSupport::TestCase
test "mama_i_papa or sheep Dolly" do
mama = Person.create!(:name=>'Mama', :age=> 40)
papa = Person.create!(:name=>'Papa', :age=> 40)
son = Person.create!(:name => 'Son', :age => 10, :mama => mama, :papa => papa)
Person.find_in_batches(:conditions => "age < 12") do |group|
group.each do |person|
puts "I am #{person.name}"
has_papa = false
has_mama = false
if person.mama
puts "My mom is #{person.mama.name}"
has_mama = true
end
if person.papa
puts "My Dad is #{person.papa.name}"
has_papa = true
end
assert has_papa && has_mama, "and i was cloned"
end
end
end
end
queries from test.log
SELECT * FROM `people` WHERE (`people`.mama_id = 3) AND (age < 12) ORDER BY people.id ASC LIMIT 1 SELECT * FROM `people` WHERE (`people`.papa_id = 3) AND (age < 12) ORDER BY people.id ASC LIMIT 1
rake test results
rake test
(in /opt/ror/edge)
/opt/ruby-enterprise-1.8.6-20090201/bin/ruby -Ilib:test "/opt/ruby-enterprise-1.8.6-20090201/lib/ruby/gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb" "test/unit/person_test.rb"
Loaded suite /opt/ruby-enterprise-1.8.6-20090201/lib/ruby/gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader
Started
I am Son
F
Finished in 0.054297 seconds.
1) Failure:
test_mama_i_papa_or_sheep_Dolly(PersonTest)
[/test/unit/person_test.rb:22:in `test_mama_i_papa_or_sheep_Dolly'
/test/unit/person_test.rb:10:in `each'
/test/unit/person_test.rb:10:in `test_mama_i_papa_or_sheep_Dolly'
/test/unit/person_test.rb:9:in `test_mama_i_papa_or_sheep_Dolly']:
and i was cloned.
is not true.
1 tests, 1 assertions, 1 failures, 0 errors
the reason i am posting this comment - I've been there with my implementation (I just called it cursor). this is what I came up with after fix. Scope with_scope to fetch only, do yeild outside of the cursor scope I tried to to use with_exclusive_scope, but this would remove potentially scope set before the cursor is run
module Uping
module ActiveRecordCursor
def cursor(conditions={})
limit = 1000
callback = nil
batch_counter = 0
if conditions.is_a?(Hash)
limit = conditions.delete(:limit) || limit
callback = conditions.delete(:callback)
end
conditions[:order]="#{table_name}.#{primary_key}" unless conditions
rows = cursor_next_scoop(conditions, limit, 0)
while rows.any?
next_max_id = rows.map(&:id).max
batch_size = rows.size
#using map! - replace elements of the list by the result
#of the block - this way we may give hint to GC to discard
rows.map! { |record|
yield record
nil
}
batch_counter += 1
callback.call(
:count => batch_counter,
:size => batch_size
) if callback;
rows = cursor_next_scoop(conditions, limit, next_max_id)
end
end
private
def cursor_next_scoop(conditions, limit, next_max_id)
with_scope(:find => conditions) do
find(:all,
:conditions => ["#{table_name}.#{primary_key} > ?", next_max_id],
:limit => limit
)
end
end
end
end
usage
class PersonTest < ActiveSupport::TestCase
test "mama_i_papa or sheep Dolly" do
mama = Person.create!(:name=>'Mama', :age=> 40)
papa = Person.create!(:name=>'Papa', :age=> 40)
son = Person.create!(:name => 'Son', :age => 10, :mama => mama, :papa => papa)
Person.cursor(:conditions => "age < 12") do |person|
puts "I am #{person.name}"
has_papa = false
has_mama = false
if person.mama
puts "My mom is #{person.mama.name}"
has_mama = true
end
if person.papa
puts "My Dad is #{person.papa.name}"
has_papa = true
end
assert has_papa && has_mama, "and i was cloned"
end
end
end
Expected results
/opt/ror/edge/test/unit$ ruby -I../ person_cursor_test.rb Loaded suite person_cursor_test Started I am Son My mom is Mama My Dad is Papa . Finished in 0.278581 seconds. 1 tests, 1 assertions, 0 failures, 0 errors