Uploading large files to Rails with Merb
As you know Rails does bad on handling file upload, a large file will block your Rails app a long while, make it busy on receiving the file and can’t give response to other visitors, make them upset and leave you alone.
One solution is using merb to handle file upload for rails. The latest Merb that build on Rack(a cool framework who help you dealing with all kinds of http servers) does a really good job on uploading.
First, install merb:
—- rubysudo gem install merb
1 2 3 4 5 6 7 |
Second, create a merb app in your rails dir:
--- ruby
merb-gen app uploader
cd uploader
|
You can ignore all other files except config/rack.rb, this is the only file we need to modify.
Currently there’s only one line in the file:
1 |
run Merb::Rack::Application.new |
It will ask merb to handle the http request come from rack.
Let us change this file to:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
require 'cgi' class File def to_s path end end # build a new handler to handler rack's request class Uploader def call(env) # leverage merb's utility to parse the request. # Merb will save the file to a tempfile and save the tempfile's path in request's param request = Merb::Request.new(env) params = request.params # pass the params directly to the real (rails) app result = post("http://someplace.com/api", hash_to_params(params)).split("\n")[-1] # processing result or just ignore it ... end private def post(url, params="") curl_cmd = "curl -H \"Content-type: application/x-www-form-urlencoded\" #{url} -d \"#{params}\"" puts "curl_cmd = #{curl_cmd}" f = IO.popen(curl_cmd +" 2>&1") result = f.read f.close result end def hash_to_params(hash) hash.map do |k, v| if v.kind_of? Hash h = {} v.each { |kk, vv| h["#{k}[#{kk}]"] = vv } hash_to_params h else "#{k}=#{CGI.escape v.to_s}" end end.join("&") end end run Uploader.new |
Run merb by
merb p 1234 -c 1 -e production -d-
-
Remember to config your apache or your favorite webserver to redirect all request from /uploader to port 1234 (Your merb uploader is listening here!).
Pretty easy, isn’t it?
