Need help refactoring a controller, perhaps add threading?

Good morning,

I’ve been working on my first Rails app. I’m replacing an old Perl
script that scrapes a bunch of data from an Oracle database, generates a
bunch of charts then builds a static webpage with the charts.

I’ve re-built it in Rails, with about 25% of the code it took to do in
Perl and the users can now get dynamic charts instead of day old charts
(or whenever the batch runs).

I have a view that contains two columns, one for a list of charts and
the other with a div container for the charts (called chartDisplay).

I have a link for a chart like below:
<%= link_to_remote( “Activities by Request”,
:update => “chartDisplay”,
:url =>{ :action => :activities_by_request,
:name => @project.name }) %>

This in turn calls the following in my controller:
def activities_by_request
@chart_data = ActiveRecord::Base.connection().execute(“very long
complicated SQL query that I haven’t figured out how to refactor with
ActiveRecord yet…”)
outfile =
File.open(‘public/data/activities_by_request_’+params[:name]+‘.csv’,
‘wb’)
CSV::Writer.generate(outfile) do |csv|
@chart_data.each do |cd|
csv << [cd[“count”],cd[“request_title”],cd[“state”]]
end
end
outfile.close
exec(“charting/RequestByProject.jar”,params[:name])
render_text ‘
<img
src="…/…/images/charts/requestByProjectBurnSmall_’+params[:name]+‘.png’
end

(Pastebin URL: http://pastebin.com/m8445781)

My problem is occurring at the exec() statement, it completely takes
over and freezes everything until it’s finished at which time the
render_text inserts the generated chart into my div. This process only
takes 4 or so seconds but in that 4 or so seconds I would like to put a
message inside the div saying “Your chart is being built” with my
spinner animation under it so the user knows that something is going on.

I put the exec in a Thread.new{} but I’m not too familiar with how
threads function so my render_text line to put up the image was firing
before the chart was built. How would I correctly make a look to check
thread.alive? to see if it’s finished or not?

Ultimately I would like for the user to click the link, populate the div
with the text and spinner, generate the chart and place it in the div
when finished. I also wasn’t sure if this was a job for an RJS template
but the few screencasts I watched didn’t give me the impression I could
do what I needed with an RJS template (which I could be very well
wrong).

However, as my first Rails app, what I’ve accomplished so far just by
tutorials and the Agile Rails book is far greater than what I could do
in the Perl tool (not to mention adding further capabilities and making
it easier to maintain).

Thanks in advance for any responses!

Definately a job for rjs. You could do something like this in your
controller method (which you call with link_to_remote)

render :update do |page|
page.replace_html “div_id”, :partial => “results”
end

let me know if you need more help.

Daniel Owen van Dommelen wrote:

Definately a job for rjs. You could do something like this in your
controller method (which you call with link_to_remote)

render :update do |page|
page.replace_html “div_id”, :partial => “results”
end

let me know if you need more help.

Could you elaborate on how I can work that logic into an RJS template?

Where were :partial come into play?

I appreciate it, thanks!

Matthew W. wrote:

Daniel Owen van Dommelen wrote:

Definately a job for rjs. You could do something like this in your
controller method (which you call with link_to_remote)

render :update do |page|
page.replace_html “div_id”, :partial => “results”
end

let me know if you need more help.

Could you elaborate on how I can work that logic into an RJS template?

Where were :partial come into play?

I appreciate it, thanks!

The partial is simply some view code you want rendered inside the target
div. So basically you create a partial where your chart is rendered. You
generate your chart data inside the controller and then you do the
render :update do |page| stuff to insert the chart partial inside the
div. In your case may even be better to do just this:

render :update do |page|
page.reaplce_html “target_div”, ‘
<img
src="…/…/images/charts/requestByProjectBurnSmall_’+params[:name]+’.png’
end

Daniel Owen van Dommelen wrote:

Matthew W. wrote:

Daniel Owen van Dommelen wrote:

Definately a job for rjs. You could do something like this in your
controller method (which you call with link_to_remote)

render :update do |page|
page.replace_html “div_id”, :partial => “results”
end

let me know if you need more help.

Could you elaborate on how I can work that logic into an RJS template?

Where were :partial come into play?

I appreciate it, thanks!

The partial is simply some view code you want rendered inside the target
div. So basically you create a partial where your chart is rendered. You
generate your chart data inside the controller and then you do the
render :update do |page| stuff to insert the chart partial inside the
div. In your case may even be better to do just this:

render :update do |page|
page.reaplce_html “target_div”, ‘
<img
src="…/…/images/charts/requestByProjectBurnSmall_’+params[:name]+’.png’
end

Now how do I tie in a spinner and then fire off the exec statement
without freezing my app for 5 seconds? That’s the key issue I’m trying
to tackle.

Thanks for the responses!

don’t remember the exact syntax, but check api.rubyonrails.org for that.
just check the link_to_remote section, it explains the spinner stuff

Daniel Owen van Dommelen wrote:

don’t remember the exact syntax, but check api.rubyonrails.org for that.
just check the link_to_remote section, it explains the spinner stuff

think it was something like :loading => “yourgifhere.gif”

Isak H. wrote:

On 9/12/07, Matthew W. [email protected] wrote:

before the chart was built. How would I correctly make a look to check
thread.alive? to see if it’s finished or not?

Most web frameworks frown upon user created/managed threads.

This would be fairly esoteric imo, but if you really realy insist,
look into BackgrounDRb for running the job asynchronously. Would need
some kind of AJAX push library to feed the results to clients when
done.

Ultimately I would like for the user to click the link, populate the div
with the text and spinner, generate the chart and place it in the div
when finished. I also wasn’t sure if this was a job for an RJS template
but the few screencasts I watched didn’t give me the impression I could
do what I needed with an RJS template (which I could be very well
wrong).

Hmm… I’d go with two partials.

When clicking, load the ‘work in progress’ div. Once that completes,
start a second remote function to fetch the real contents, e.g.
through remote_function’s :completed callback.

-Isak

That sounds like the best option to me (logically anyway).

Could you provide a reference or the basic calls I would use to
accomplish calling the functions and working with the :completed
callback?

On 9/12/07, Matthew W. [email protected] wrote:

before the chart was built. How would I correctly make a look to check
thread.alive? to see if it’s finished or not?

Most web frameworks frown upon user created/managed threads.

This would be fairly esoteric imo, but if you really realy insist,
look into BackgrounDRb for running the job asynchronously. Would need
some kind of AJAX push library to feed the results to clients when
done.

Ultimately I would like for the user to click the link, populate the div
with the text and spinner, generate the chart and place it in the div
when finished. I also wasn’t sure if this was a job for an RJS template
but the few screencasts I watched didn’t give me the impression I could
do what I needed with an RJS template (which I could be very well
wrong).

Hmm… I’d go with two partials.

When clicking, load the ‘work in progress’ div. Once that completes,
start a second remote function to fetch the real contents, e.g.
through remote_function’s :completed callback.

-Isak

On 9/12/07, Matthew W. [email protected] wrote:

look into BackgrounDRb for running the job asynchronously. Would need

Could you provide a reference or the basic calls I would use to
accomplish calling the functions and working with the :completed
callback?

See ActionView::Helpers::Prototype*/JavaScript*/Scriptaculous in the API
docs.

Daniel already explained how you’d write actions that update certain
parts of the page, see ActionController::Base#render and
ActionView::Base for more info.

I think something like this should work:

<%= link_to_remote(“Load data”, :url => {:action =>
“replace_div_with_spinner”}, :complete => remote_function(:url =>
{:action => “replace_div_with_real_contents”}) ) %>

HTH,
Isak

I think something like this should work:

<%= link_to_remote(“Load data”, :url => {:action =>
“replace_div_with_spinner”}, :complete => remote_function(:url =>
{:action => “replace_div_with_real_contents”}) ) %>

HTH,
Isak

I like this one :slight_smile: Never though about calling a remote function inside
the :complete clause.