2011-01-16 6 views
13

Estoy trabajando en la implementación de Ajax-Upload para cargar fotos en mi aplicación Rails 3. La documentación dice:Rails 3 obtener datos de entrada sin procesar y escribirlo en el archivo tmp

  1. For IE6-8, Opera, older versions of other browsers you get the file as you normally do with regular form-base uploads.

  2. For browsers which upload file with progress bar, you will need to get the raw post data and write it to the file.

Entonces, ¿cómo puedo recibir los datos enviados primas en mi controlador y escribir en un archivo tmp por lo que mi controlador entonces puede procesarlo? (En mi caso el controlador está haciendo alguna manipulación de la imagen y guardar en S3.)

Alguna información adicional:

Como estoy configurado en este momento el cargo está pasando estos parámetros:

Parameters: 
{"authenticity_token"=>"...", "qqfile"=>"IMG_0064.jpg"} 

acción ... y el CREAR ve así:

def create 
    @attachment = Attachment.new 
    @attachment.user = current_user 
    @attachment.file = params[:qqfile] 
    if @attachment.save! 
     respond_to do |format| 
      format.js { render :text => '{"success":true}' } 
     end 
    end 
end 

... pero me da este error:

ActiveRecord::RecordInvalid (Validation failed: File file name must be set.): 
    app/controllers/attachments_controller.rb:7:in `create' 
+0

Acabo de lanzar un ejemplo de ajax upload in rails 3 + Uploadify aquí: https://github.com/apneadiving/Pic-upload---Crop-in-Ajax. Espero que pueda ayudar – apneadiving

Respuesta

26

Eso es porque params [: qqfile] no es un objeto UploadedFile sino una cadena que contiene el nombre del archivo. El contenido del archivo se almacena en el cuerpo de la solicitud (accesible al usar request.body.read). Por supuesto, no puede olvidar la compatibilidad con versiones anteriores, por lo que aún debe admitir UploadedFile.

Así que antes de poder procesar el archivo de una manera uniforme, lo que tienes que coger dos casos:

def create 
    ajax_upload = params[:qqfile].is_a?(String) 
    filename = ajax_upload ? params[:qqfile] : params[:qqfile].original_filename 
    extension = filename.split('.').last 
    # Creating a temp file 
    tmp_file = "#{Rails.root}/tmp/uploaded.#{extension}" 
    id = 0 
    while File.exists?(tmp_file) do 
    tmp_file = "#{Rails.root}/tmp/uploaded-#{id}.#{extension}"   
    id += 1 
    end 
    # Save to temp file 
    File.open(tmp_file, 'wb') do |f| 
    if ajax_upload 
     f.write request.body.read 
    else 
     f.write params[:qqfile].read 
    end 
    end 
    # Now you can do your own stuff 
end 
+4

Gracias! Esto funcionó muy bien! Como comentario, encontré (después de que me pusiste en el camino correcto) que en mi caso al menos 'tmp_file = Tempfile.new (filename)' funciona igual de bien mientras que es un poco más limpio que tu código en '' Creando una temperatura nota del archivo' Ambas formas funcionan bien. ¡Gracias! – Andrew

+0

'f.write params [: qqfile] .read' - esto debería ser' f.write params [: qqfile] .tempfile.read' de lo contrario no se almacena ningún archivo – Toshe

+0

No, no debería, UploadedFile # read es un atajo para UploadedFile # tempfile.read para que el código haga lo mismo en ambos casos –

5

probarlo, añadir lib/qq_file.rb:

# encoding: utf-8 
require 'digest/sha1' 
require 'mime/types' 

# Usage (paperclip example) 
# @asset.data = QqFile.new(params[:qqfile], request) 
class QqFile < ::Tempfile 

    def initialize(filename, request, tmpdir = Dir::tmpdir) 
    @original_filename = filename 
    @request = request 

    super Digest::SHA1.hexdigest(filename), tmpdir 
    fetch 
    end 

    def self.parse(*args) 
    return args.first unless args.first.is_a?(String) 
    new(*args) 
    end 

    def fetch 
    self.write @request.raw_post 
    self.rewind 
    self 
    end 

    def original_filename 
    @original_filename 
    end 

    def content_type 
    types = MIME::Types.type_for(@request.content_type) 
     types.empty? ? @request.content_type : types.first.to_s 
    end 
end 

en este tipo assets_controller :

def create 
    @asset ||= Asset.new(params[:asset]) 

    @asset.assetable_type = params[:assetable_type] 
    @asset.assetable_id = params[:assetable_id] || 0 
    @asset.guid = params[:guid] 
    @asset.data = QqFile.parse(params[:qqfile], request) 
    @asset.user_id = 0 
    @success = @asset.save 

    respond_with(@asset) do |format| 
    format.html { render :text => "{'success':#{@success}}" } 
    format.xml { render :xml => @asset.to_xml } 
    format.js { render :text => "{'success':#{@success}}"} 
    format.json { render :json => {:success => @success} } 
    end 
end 

javascript:

var photo_uploader = new qq.FileUploader({ 
    element: document.getElementById('photo-button'), 
    multiple: true, 
    action: '/assets', 
    allowedExtensions: ['png', 'gif', 'jpg', 'jpeg'], 
    sizeLimit: 2097152, 
    params: {guid: $('#idea_guid').val(), assetable_type: 'Idea', klass: 'Picture', collection: true} 
}); 
1

Otra solución es:

gem 'rack-raw-upload', :git => 'git://github.com/tb/rack-raw-upload.git' 

y en config.ru:

require 'rack/raw_upload' 
use Rack::RawUpload 

y utilizar params [: Archivo] en el controlador.

Cuestiones relacionadas