Rorcraft Blog

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?

Contact

We love to hear about your web projects.
Email:
Sydney: +61 421 591 943
Hong Kong:+852 6901 2682

Categories