views:

115

answers:

2

I have a time taking task in my controller for which I want to trigger a simple progress bar/progress status in my view.

In my controller I have something like

threads = []
total.times do |x|
    Thread.new {
        the_time_taking_task(x)
        #Something here to trigger the progressbar in the view
    }
end

threads.each { |aThread|  aThread.join }
render :action => 'some_action'    

I can't put a render in there because it throws a double render error. I tried putting a render and return there and I got 'return can't jump across threads' error

I am trying render as it seems to be the only way my controller can talk to view. Is my approach wrong ?

Would want something simple like this in the view which applies the progress bar width through that call

<div style="width: <%= (percent_val)%>px; ">

Please advice.

+4  A: 

Yes it's a wrong approach.

The Web is stateless, and you can't block a process to render view and get it after by another request.

The good way is :

1) Generate a queue tasking instead of your thread. You can use delayed_job, resque or queue system, like rabbitMQ or beanstalkD

2) Add a controller to check if the process in your queue is end and how is progress. Inside, you put the queue id and check if is end or not and return the progress percent.

The easiest way is do that by Ajax.

shingara
+1  A: 

Yes, your approach is wrong.

shingara explains this well.

I'm offering a slightly more concrete solution for you.

To get the effect you want, you basically need the following steps:

  1. Offload the thread into a background job server. Checkout resque or delayed_job.
  2. Have the background job write the progress to database or some persistant medium.
  3. In Rails, write an action that returns the current progress (as json or xml)
  4. In your view, write a periodic ajax request that calls the action written in step 3.
  5. update the view accordingly.

You're done! :D

Aaron Qian