2011-08-08 10 views
5

मैंने पृष्ठभूमि में कुछ बहुत बड़ी फ़ाइलों पर कुछ प्रसंस्करण करने के लिए बस रैक का उपयोग करना शुरू कर दिया है, और मुझे यह समझने में परेशानी हो रही है कि फ़ाइल को एक रिस्क्यू कार्यकर्ता को कैसे पास किया जाए। मैं फ़ाइल अपलोड को संभालने के लिए रेल का उपयोग करता हूं, और रेल फॉर्म से अपलोड की गई प्रत्येक फ़ाइल के लिए ActionDispatch::Http::UploadedFile ऑब्जेक्ट बनाता है।संसाधित करने के लिए कार्यकर्ता को पुन: सहेजने के लिए अपलोड की गई फ़ाइल भेजना

कैसे एक resque कार्यकर्ता को इस फाइल को भेज सकता हूँ? मैं सिर्फ अस्थायी फ़ाइल और मूल फ़ाइल नाम के पथ नाम की एक कस्टम हैश भेजने की कोशिश की, लेकिन मैं अब और resque कार्यकर्ता में अस्थायी फ़ाइल नहीं खोल सकते (सिर्फ एक सामान्य Errno::ENOENT - No such file or directory), क्योंकि रेल अनुरोध समाप्त होने के बाद कि अस्थायी फ़ाइल को नष्ट करने लगता है ।

उत्तर

5

Http::UploadedFile अनुरोध समाप्त होने के बाद पहुंच योग्य नहीं है। आपको फ़ाइल कहीं कहीं लिखनी होगी (या एस 3 का उपयोग अस्थायी भंडारण के रूप में करें)। आपके द्वारा लिखी गई फ़ाइल के पथ को पास करें।

+0

एकमात्र तरीका जैसा लगता है। मैं प्रसंस्करण से पहले फ़ाइल को आगे बढ़ाना और बाद में हटाना नहीं चाहता था। धन्यवाद। –

5

मैंने बस ऐसा करने की कोशिश करने में दो दिन बिताए और आखिरकार इसे समझ लिया। आपको फ़ाइल को बेस 64 एन्कोड करने की आवश्यकता है ताकि इसे जेसन में क्रमबद्ध किया जा सके। तो फिर तुम कार्यकर्ता में यह डिकोड और बनाने की जरूरत है एक नया

ActionDispatch::Http::UploadedFile

यहाँ सांकेतिक शब्दों में बदलना और resque को पारित करने के लिए बताया गया है:

// You only need to encode the actual file, everything else in the 
// ActionDispatch::Http::UploadedFile object is just string or a hash of strings 

file = params[:file] // Your ActionDispatch::Http::UploadedFile object 
file.tempfile.binmode 
file.tempfile = Base64.encode64(file.tempfile.read) 

Resque.enqueue(QueueWorker, params) 

और यहाँ डिकोड और भीतर एक वस्तु को वापस परिवर्तित करने का तरीका बताया आपका कार्यकर्ता

class QueueWorker 
    @queue = :main_queue 

    def self.perform(params) 
     file = params['file'] 
     tempfile = Tempfile.new('file') 
     tempfile.binmode 
     tempfile.write(Base64.decode64(file['tempfile'])) 

     // Now that the file is decoded you need to build a new 
     // ActionDispatch::Http::UploadedFile with the decoded tempfile and the other 
     // attritubes you passed in. 

     file = ActionDispatch::Http::UploadedFile.new(tempfile: tempfile, filename: file['original_filename'], type: file['content_type'], head: file['headers']) 

     // This object is now the same as the one in your controller in params[:file] 
    end 
end 
+3

मैं यह कर की सिफारिश नहीं होगा, जब तक आप यह सुनिश्चित करें कि आपकी फ़ाइलों को कुछ सौ KB से अधिक होना कभी नहीं होगा रहे हैं। फ़ाइल को डिस्क/एस 3/आदि में लिखना और उस पथ को रेस्क्यू जॉब में पास करना इसे संभालने का सही तरीका है। – pnomolos

+0

निश्चित रूप से @pnomolos से सहमत हैं कि यह बड़ी फ़ाइलों के लिए अच्छा नहीं है, लेकिन यदि आप छोटी फ़ाइलों (जैसे 5-10 केबी सीएसवी) से निपट रहे हैं तो यह एक चालाक हैक है जहां उन्हें S3 पर अपलोड करने की परेशानी नहीं है और फिर फिर से जब आपको उनकी आवश्यकता होती है तो उन्हें डाउनलोड करना। – ACIDSTEALTH