3

序章

複数のテーブルがあるアプリがあります。関連付けがある場合とない場合があります。

一部のテーブルには、約100,000のエントリを保持する必要があります。

このアプリは、Ruby1.9でRails3.2を使用しており、Herokuでホストされています。必要に応じて労働者にアクセスできます。

問題の要件

アプリの重要な要件は、ユーザーがデータをCSVとしてエクスポートできるようにすることです。この要件は、ユーザーがエクスポートするデータをフィルタリングできるようにすることですが、現時点では、次のように心配する必要はありません。以下のデータでは、エクスポートするデータをハードコーディングしていますが、これにより、テーブル全体をエクスポートするだけのrakeタスクを作成することはできなくなります。

また、実装されたメソッドは、不必要なコードの繰り返しを回避するために、複数のテーブルで使用できるように因数分解する必要があります。

現在のソリューション

アプリにdelayed_jobを実装し、ジョブでCSV生成を実行しています。これを行っている間、私はここhttp://www.ayokasystems.com/blog/delegating-long-running-jobs-in-rails/from'abdullah 'にある解決策に従っています。

アイデアは、CSV形式でデータを生成し、それをUserJobsテーブルのLONGTEXTフィールドに保存して、ユーザーが完了後、後でダウンロードできるようにすることです。

問題

上記のチュートリアルで使用した方法は、一度に100,000レコードのジョブを実行するまで、アプリで正常に機能します。これを克服するために、performメソッドにcool find_each関数を追加しようとしましたが、遅延したジョブワーカーは、処理しようとするたびにエラーを報告します。

[Worker(host:*** pid:18637)] ReportJob failed with NoMethodError: undefined method `each' for #<Title:0x007ff20c1ec1b0> - 0 failed attempts
[Worker(host:*** pid:18637)] ReportJob failed with NoMethodError: undefined method `each' for #<Title:0x007ff20ec47f18> - 1 failed attempts
[Worker(host:*** pid:18637)] 2 jobs processed at 10.5219 j/s, 2 failed ... 

私のperformメソッドのコードは次のとおりです。

def perform
  Title.find_each do |titles|
    csv_data = CSV.generate do |csv|
      titles.each do |t|
        csv << t.to_csv
      end
    end
    user_job = UserJob.find(user_job_id)
    user_job.update_attribute :data, csv_data
  end
end

誰かが問題が何であるかを見ることができますか、私は私が物事をループしている方法で私がちょうど愚かな間違いをしたと思っています。

問題の要件を達成する方法について他の提案を歓迎しますが、Herokuには制限があることを覚えておいてください。

4

2 に答える 2

3

それぞれを反復しようとしていますが、この場合のタイトルはタイトルのインスタンスです(配列ではありません)。

csv_vals = []
columns = [:name, :release_date, :studio]

Title.find_each(:select => columns) do |title| 
  columns.each {|value| csv_vals << "#{title[value]}"}
end

# comma separated string 
csv_string = csv_vals.join(',')

CSV 文字列を定式化するよりエレガントな方法がありますが、実験するのが面倒です。

重要なのは、必要な列に対してのみ SELECT を実行していることです。100,000 レコードの場合、DB 通信の帯域幅が大幅に削減されます。find_eachだけで、各行のすべての列を取得でき、それらは必要ありません。

于 2012-04-20T12:05:28.517 に答える
1

find_eachコレクションではなくブロックに単一のレコードを生成するため、単一のレコードでエラーが発生eachしました。find_in_batchesを確認するか、単一のレコードを使用するようにコードを修正してください。

Title.find_each do |title|
  CSV.generate do |csv|
    csv << title.to_csv
  end
  user_job = UserJob.find(user_job_id)
  user_job.update_attribute :data, csv_data
end
于 2012-04-20T11:52:07.427 に答える