ActiveRecord::Base.each instance method
Reported by Guillermo Álvarez | May 17th, 2008 @ 06:15 PM | in 2.x
[PATCH] These patch add: ActiveRecord::Base.each ( User.each {|u| u.name} ) ActiveRecord::Base.map ActiveRecord::Base.collect
But with the diference with User.all.each that just one user is fetch from the database at a time. An simple and efficient way to don't load all the database in memmory.
With migrations between two or more databases, is common to do something like
User.find(:all).each {|u| ... } that will load all the records in memmory.
Ruby-proff says that managing that big array is not the better way.
With these patch you can do something like these.
User.each :conditions => ["users.created_at > ?", Time.now-5.months] do |u| NewUser.schema.create({ :name => u.name.Capitalize :email => validate_email u.email ... }) end
These patch pass all test, and have news ones.
Any comment are wellcome.
Comments and changes to this ticket
-
wildchild May 17th, 2008 @ 09:07 PM
My 5 cents for you (if i right understand your approach):
ActiveRecord::Base.each.fetch(10) # fetch 10 records instead 1 (for small rows in example)
Maybe use will_paginate there?
-
Guillermo Álvarez May 17th, 2008 @ 08:15 PM
ActiveRecord::Base.each
ActiveRecord::Base.map
ActiveRecord::Base.collect
With migrations between two or more databases, is common to do something like
User.find(:all).each {|u| ... } that will load all the records in memmory.
Ruby-proff says that managing that big array is not the better way.
For my personal projects I use something like these:
http://github.com/guillermo/acti...
User.each :conditions => ["users.created_at > ?", Time.now-5.months] do |u|
NewUser.schema.create({
:name => u.name.Capitalize
:email => validate_email u.email
... })
end
If someone think it could be interesting, i can try to make a patch.
Thanks
-
Guillermo Álvarez May 17th, 2008 @ 08:24 PM
My situation is these:
desc 'Copy Posts from the phpbB3 table to the new forum'
task :copy_posts => :environment do
BbTopic.find(:all).each do |bb|
f = Post.create({
:title => conv.iconv(bb.topic_title),
:user_id => bb.topic_poster,
:forum_id= bb.forum_id,
...})
end
end
If i run that i will get a huge array in memory that i doesn't want, so i change
BbTopic.find(:all).each do |bb|
to
BbTopic.each do |bb|
that just load one record a time.
-
Tarmo Tänav May 18th, 2008 @ 06:53 PM
Something like this has already been proposed:
-
-
Joshua Peek August 29th, 2008 @ 04:41 PM
- → Tag changed from to enhancement
- → State changed from new to stale
-
Guillermo Álvarez September 9th, 2008 @ 01:37 PM
- → Tag changed from enhancement to activerecord enhancement
Hi.
There is a patch to do for example Post.each.
Please giveme comments since is my first patch to rails.
-
Guillermo Álvarez September 10th, 2008 @ 09:27 AM
- → Assigned user changed from to Joshua Peek
-
Guillermo Álvarez September 10th, 2008 @ 09:27 AM
- → Title changed from ActiveRecord::Base.each instance method to [PATCH] ActiveRecord::Base.each instance method
-
Pratik September 10th, 2008 @ 10:31 AM
- → Tag changed from activerecord enhancement to activerecord enhancement patch
- → Title changed from [PATCH] ActiveRecord::Base.each instance method to ActiveRecord::Base.each instance method
-
Jeremy Kemper September 10th, 2008 @ 06:12 PM
- → Milestone changed from to 2.2
- → State changed from stale to open
-
Joshua Peek September 10th, 2008 @ 06:30 PM
- → Assigned user changed from Joshua Peek to Jeremy Kemper
-
Pratik October 17th, 2008 @ 05:13 PM
- → Milestone changed from 2.2 to 2.x
-

José Valim October 19th, 2008 @ 11:36 AM
Hi Guillermo Álvarez,
Would not be nice if your patch takes into account the option :limit and :interval?
For example:
@@@ruby Account.each(:interval => 10) do |account|
# ...end
This would query the database using 10 in 10 objects. The limit would be used if I don't want to go through all the database: @@@ruby Account.each(:interval => 10, :limit => 100) do |account| # ... endI have an implementation that I use on my projects (it's not totally abstracted as in your patches), but if it helps:
@@@ruby def slow_each(options = {})
total = options.delete(:limit) || self.count(:conditions => options[:conditions]) options[:limit] = options.delete(:interval) || 1000 offset = 0 while total - offset > 0 options[:offset] = offset self.find(:all, options).each do |record| yield(record) end offset += options[:limit] endend
For fast each, we can use: @@@ruby def fast_each(options = {}) total = options.delete(:limit) || self.last.id default_conditions = options.delete(:conditions) options[:limit] = options.delete(:interval) || 1000 offset = 0 while total - offset > 0 options[:conditions] = self.__send__(:merge_conditions, default_conditions, ['id BETWEEN ? AND ?', offset + 1 , offset + options[:limit]]) self.find(:all, options).each do |record| yield(record) end offset += options[:limit] end end
Please Login or create a free account to add a new comment.
You can update this ticket by sending an email to from your email client. (help)
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
Source available from github
The Git repository resides at http://github.com/rails
Check out the current development trunk (Edge Rails) with:
git clone git://github.com/rails/rails.git
Creating or reviewing a patch
See the contributor guide.
Creating a feature request
Please don't. If you want a new feature in Rails, you'll have to pull up your sleeves and get busy yourself. Or convince someone else to do it. See the contributor guide on how to get going. But posting them here is just going to lead to ticket root.
Creating a bug report
When creating a bug report, be sure to include as much relevant information as possible. Post the code sample that causes the problem. Preferably, alter the unit tests and show through either changed or added tests how the expected behavior is not occuring.
Security vulnerabilities should be reported via an email to security@rubyonrails.org, do not use trac for reporting security vulnerabilities. All content in trac is publicly available as soon as it is posted.
Then don't get your hopes up. Unless you have a "Code Red, Mission Critical, The World is Coming to an End" kinda bug, you're creating this ticket in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the ticket automatically will see any activity or that others will jump to fix it. Creating a ticket like this is mostly to help yourself start on the path of fixing the problem and for others to sign on to with a "I'm having this problem too".
