Skip to content

Instantly share code, notes, and snippets.

@elvuel
Created February 17, 2012 06:02
Show Gist options
  • Save elvuel/1851088 to your computer and use it in GitHub Desktop.
Save elvuel/1851088 to your computer and use it in GitHub Desktop.
Paperclip + valums’s file-uploader problem on Heroku
FIXED: See the next file for a working RawFileUpload class.
UPDATE: Heroku uses thin server and I use webrick. When I tried thin on my local machine, it didn't work.
So, the conclusion is there is some difference between webrick and thin that's causing the problem.
This file is related to this blog post:
http://mooooooooooo.wordpress.com/2010/12/03/paperclip-valums%E2%80%99s-file-uploader-and-middleware-continued/
The code in the blog post works fine on my local machine but not on Heroku.
# In my photos_controller.rb:
def create
# print params to log
puts "photo create params: " + params.inspect
if @photo.save
#...
end
end
The output for the params line in my local machine:
photo create params: {"photo"=>{"image"=>#<ActionDispatch::Http::UploadedFile:0x00000003fb1910 @original_filename="Desert.jpg", @content_type=image/jpeg, @headers=nil, @tempfile=#<File:/tmp/raw-upload.20110711-3169-yigmmi>>}, "authenticity_token"=>"0yvXnzV8fnsP24eAxJFH4aViG4nBMydB6O+dZ7HdY+4=", "qqfile"=>"Desert.jpg", "action"=>"create", "controller"=>"photos", "venue_id"=>"test"}
And same thing on Heroku:
photo create params: {"authenticity_token"=>"2WiyKzNC10V8op6ryCRA24zdqjvWPF7HQgsv9L95zL0=", "qqfile"=>"Desert.jpg", "action"=>"create", "controller"=>"photos", "venue_id"=>"foo"}
Clearly something is wrong there.
Here's my 'rake middleware' output on local machine:
use ActionDispatch::Static
use ActionDispatch::Static
use Rack::Lock
use ActiveSupport::Cache::Strategy::LocalCache
use Rack::Runtime
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::RemoteIp
use Rack::Sendfile
use ActionDispatch::Callbacks
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use ActionDispatch::Head
use ActionDispatch::BestStandardsSupport
use Warden::Manager
use RawFileUpload
use OmniAuth::Strategies::Facebook
run MyApp::Application.routes
And same thing on Heroku:
use ActionDispatch::Static
use ActionDispatch::Static
use Rack::Lock
use Rack::Runtime
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::RemoteIp
use Rack::Sendfile
use ActionDispatch::Callbacks
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use ActionDispatch::Head
use ActionDispatch::BestStandardsSupport
use Warden::Manager
use RawFileUpload
use OmniAuth::Strategies::Facebook
run MyApp::Application.routes
require 'mime/types'
class RawFileUpload
def initialize(app)
@app = app
end
def call(env)
if raw_file_post?(env)
convert_and_call(env)
else
@app.call(env)
end
end
private
def raw_file_post?(env)
env['HTTP_X_FILE_NAME'] &&
env['CONTENT_TYPE'] == 'application/octet-stream' &&
env['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
end
def convert_and_call(env)
# sometimes env['rack.input'] is Tempfile, sometimes StringIO => make it always StringIO
input = env['rack.input']
if input.is_a? Tempfile
input = StringIO.new(input.read)
end
env['rack.input'] = input
# convert to UTF8
tempfile = Tempfile.new('raw-upload.')
input.each do |chunk|
tempfile << chunk.force_encoding('UTF-8')
end
tempfile.flush
tempfile.rewind
multipart_hash = {
:image => {
:filename => env['HTTP_X_FILE_NAME'],
:type => MIME::Types.type_for(env['HTTP_X_FILE_NAME']).first,
:tempfile => tempfile
}
}
env['rack.request.form_input'] = env['rack.input']
env['rack.request.form_hash'] ||= {}
env['rack.request.query_hash'] ||= {}
env['rack.request.form_hash']['photo'] = multipart_hash
env['rack.request.query_hash']['photo'] = multipart_hash
@app.call(env)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment