Chcę zrobić coś na kształt przetwarzania batchowego z paskiem postępu.
Z formularza w akcji import jest wczytywany plik, który ma utworzyć tabelę.
Na razie działa dodawanie po jednej linii sterowane z przeglądarki przez periodically_call_remote.
Ale to dodaje po 1 sekundzie ekstra na każdą linię. Dodatkowo plik jest przechowywany w session.
Czy jest możliwe wywołanie “asynchronicznie” metody Line.addall(params[:file]) i w kontrolerze odpytywanie
tylko metody Line.progress. Napisałem jak widać te metody ale nie wiem jak je użyć.
Czy ktoś ma może jakiś inny pomysł na pasek postępu.
To jest tylko szkielet aplikacji (ale działający).
[code]# line.rb - model zawiera tylko jedno pole verse - przechowujące kolejne wiersze pliku wejściowego
class Line < ActiveRecord::Base
def self.add1 v
r = Line.new
r.verse = v
r.save
sleep 1 # symulacja baaardzo skomplikowanej operacji na bazie
end
def self.addall vs
vs = vs.read.split($/)
l = vs.length
@@progress = 0
vs.each_index do |i|
@@progress = (i.to_f/l.to_f*100).to_i
Line.add1 v[i]
end
end
def self.progress
@@progress
end
end[/code]
# import.html.erb
<% form_tag({:action => 'do'}, {:multipart => true}) do %>
<%= file_field_tag 'file' %><br />
<%= submit_tag %>
<% end %>
[code]# do.html.erb
<%= periodically_call_remote(:url => { :action => ‘progress’ }, :frequency => ‘1’, :update => ‘bar’) %>
def do
if params[:file].blank?
redirect_to :action=>‘import’
return
end
zamiast poniższych linii - przydałoby się wywołać ‘asynchronicznie’ addall(params[:file])
session[:file] = params[:file].read.split($/)
session[:ifile] = 0
end
def progress
i = session[:ifile]
l = session[:file].length
if i>=l
session[:file] = nil
render :inline=>"<%= javascript_tag “location=’#{url_for :action=>‘import’}’” %>", :layout=>false
else
a zamiast dwóch następnych linii pr = Line.progress
Line.add1 session[:file][i] # tworzy jeden rekord
pr = (i.to_f/l.to_f*100).to_i.to_s
render :inline=>"<span style='padding-left:#{pr}mm;background:red'>#{pr}%</span>", :layout=>false
session[:ifile] += 1
end
end
end[/code]