Rails csv import with progress bar

Hey guys, got a rails question:

I've finished creating a csv import ability in my web application that
parses a csv file and adds records into the MySQL db. I figuired it
would be nice to have a progress bar for this import process.
Unfortunately I have run into issues trying to implement this..

What I have tried right now is to call a javascript function on submit
of the form specifying the file to import. Every 5 seconds this
function creates an Ajax request to a "update_progress" method
inside my controller. What I'm seeing is that all the Ajax requests
are not called until AFTER my method "csv_import" that parses the csv
file completes (rails seems to be too busy parsing).. so all I get is
0% and then jumps to 100%. I've also tried adding a render statement
to the "update_progress" method inside the loop that parses the csv
file but this is a problem since rails only lets you render once in a
method (I'm already rendering the results at the end). Does any one
know a better way for me to display to the user the progress of my
"csv_import" method.

Basic outline of method "csv_import" and "update_progress":

$total_lines_read = 0

def csv_import
open file
read & add record for each line to the db
increment $total_lines_read
render the results
end

def update_progress
render javascript function to update the bar sending it
$total_lines_read
end

Nabeel Mr. wrote:

Hey guys, got a rails question:

I've finished creating a csv import ability in my web application that
parses a csv file and adds records into the MySQL db. I figuired it
would be nice to have a progress bar for this import process.
Unfortunately I have run into issues trying to implement this..

Oh yeah. HTTP requires very narrow events. To fix this, you must stretch one logical event out over many physical events.

Try this:

  - the "Go" button starts a periodically_call_remote
  - that calls an action
  - the action opens the CSV,
       - reads one batch from it (say 20 lines)
       - stash the current record count in the session
       - returns nothing
  - the periodically_call_remote ticks the progress bar
  - the periodically_call_remote stops when the action
       - returns JavaScript assigning 'false' to a global variable
  - the periodically_call_remote's condition is that variable

That sounds like a lot of work, but the alternatives are all worse!

And if you progress, you should have a cancel button. My system makes your reader function easier to interrupt.

Another option is to use backgroundrb to process the csv file outside
the current rails process. This has the advantage of not blocking web
requests to that process because your app is processing the file, as
well as allowing you to check in on the job periodically using the
worker id to see how it's going and to update your progress bar.

then again, getting backgroundrb running for this particular problem
may be overkill :slight_smile:

hth, Matt

Nabeel,

When you control the loop, a simple solution is "action chunking" :
cut your big task/action into smaller chunks, that chain/call themself
automatically, and display a little visual feedback between each
transition.

This process is documented here :

  words :
          http://docs.google.com/View?docid=ddmqwkxs_3972nphr5fk
  video demos :
          http://screencast.com/t/GiwRm3ziQy
          http://screencast.com/t/ba5dD9OPv6

Alain Ravet

then again, getting backgroundrb running for this particular problem
may be overkill :slight_smile:

hth, Matt

That's why I didn't mention backgroundrb. (We abuse that all the time, at my day-job, to avoid action-chunking!)

If the OP learned they could install a fragile deployment-nightmare as an excuse not to split their inner loop up into action chunks, they might behave the same way Java programmers do when they hear that threading in Java is "easy"...

I've finished creating a csv import ability in my web application that
parses a csv file and adds records into the MySQL db. I figuired it
would be nice to have a progress bar for this import process.
Unfortunately I have run into issues trying to implement this..

I had to do almost exactly this, I screen casted it and documented it here:

http://www.blognow.com.au/q/64767/Screen_cast_of_multiple_progress_bar_tracker.html

Regards

Mikel

http://lindsaar.net/