ActiveRecordをSequelっぽく扱う

module ActiveRecordHelper
  def each(opts={})
    rows = find(:all, opts)
    while rows.any?
      rows.each{|v| yield v}
      conditions =
        if opts.key? :conditions
          _conditions = opts[:conditions].clone
          _conditions.first.insert(0, 'id > ? and ')
          _conditions.insert(1, rows.last.id)
        else
          ["id > ?", rows.last.id]
        end
      new_opts = opts.merge({:conditions => conditions})
      rows = find(:all, new_opts)
    end
  end
end
class ActiveRecord::Base
  extend ActiveRecordHelper
end

とかやっておくと ActiveRecordでeachメソッドが使えるようになる。テーブル全体をなめるバッチ処理などに便利、メールのキューから全部メールを送る場合なんかは

  def send_mail v
    # メールを送る処理
  end
  MailQueue.each(:limit => 100, :order => :id, 
                   :conditions => ["status = ?", 'undeliver']){|v|
    send_mail(v)
  }

みたいな感じで処理できる。limitは取り出す数ではなくて、一度にフェチする数を指しているので、件数が多くても大丈夫。 :order には idを指定しないとまずい。