#215 open
Guillermo Álvarez

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

    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

    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

    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
  • wildchild

    wildchild May 29th, 2008 @ 12:22 AM

    Any progress with ticket?

  • Joshua Peek

    Joshua Peek August 29th, 2008 @ 04:41 PM

    • → Tag changed from “” to “enhancement”
    • → State changed from “new” to “stale”
  • Guillermo Álvarez

    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

    Guillermo Álvarez September 10th, 2008 @ 09:27 AM

    • → Assigned user changed from “” to “Joshua Peek”
  • Guillermo Álvarez

    Guillermo Álvarez September 10th, 2008 @ 09:27 AM

    • → Title changed from “ActiveRecord::Base.each instance method” to “[PATCH] ActiveRecord::Base.each instance method”
  • Pratik

    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

    Jeremy Kemper September 10th, 2008 @ 06:12 PM

    • → Milestone changed from “” to “2.2”
    • → State changed from “stale” to “open”
  • Joshua Peek

    Joshua Peek September 10th, 2008 @ 06:30 PM

    • → Assigned user changed from “Joshua Peek” to “Jeremy Kemper”
  • Pratik

    Pratik October 17th, 2008 @ 05:13 PM

    • → Milestone changed from “2.2” to “2.x”
  • José Valim

    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|
        # ...
      end
    

    I 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]
    end
    
    

    end

    
    
    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".

Shared Ticket Bins