问题
I am uploading a tab-delimited document and processing in the controller. Everything works fine, but can take some time on a large file. I want to move this to a delay_job, which I have working elsewhere in my app, but as this is in the controller, cannot be called in the same way.
The form calls on the process_file action, which in turn calls on the salesupload action. How should I turn this into a background job?
class SalesController < ApplicationController
def salesupload(file)
uploaded_io = file.read
numrows = "uploaded_io.size"
FasterCSV.parse(uploaded_io, {:headers => true, :col_sep =>"\t"}).each do |row_data|
full, upc, _discard, isrc = row_data[26].match(/^([^_]+)(_(.+))?/).to_a
new_record = AppleSale.new(
'provider' => row_data[0],
'provider_country' => row_data[1],
'vendor_identifier' => row_data[2]
)
new_record.save
end
end
def process_file
file = params[:apple_sale][:tsv_file]
salesupload(file)
end
end
回答1:
I found when I had to do this that the method defined in the controller has to be a class method. I can't remember why this was, I think it had to do with having a more explicit receiver. So what I would do is make the salesupload method a class method, and then just call .delay
on it.
def self.salesupload(files)
# code
end
def process_file
file = params[:apple_sale][:tsv_file]
SalesController.delay.salesupload(file)
head :no_content
end
And you should be good to go! I also made my original method (process_file
in this case) called via AJAX, and then I appended the head :no_content
so that it returned something without needing a redirect or anything.
回答2:
I wrote a gem called delayed_action to do this.
In this case you'd write
delayed_action [:sales_upload]
and that's it.
回答3:
I guess you should move this code to a model or a separated class (for instance inside the lib folder). But that is just a matter of organization and best practices.
About the running this code in background, you have many options. If you want to use delayed_job I guess you should watch this screencast: http://railscasts.com/episodes/171-delayed-job
but basically, after setting up delayed job, you just use something like send_later(:process_file) to tell to run that project in background. It is pretty straightforward, your command and data structure will be saved in a database table and later a separated process can execute it. I imagine that after watching the railscast you will have your answers ;)
来源:https://stackoverflow.com/questions/12956661/controller-action-to-delayed-job