2011-06-28 31 views
29

Estoy usando Backbone.js en una aplicación de Rails y necesito subir archivos como parte de uno de los modelos Backbone.Carga de archivos con Backbone

No creo que Backbone permita la carga de archivos de varias partes de fábrica. ¿Alguien ha logrado que funcione a través de algún plugin o con otra lib externa? ¿Cómo puedo extender Backbone.js para soportar esto?

Respuesta

20

Respondiendo a mi propia pregunta después de algunos meses de prueba utilizando diferentes métodos. Mi solución es la siguiente (con Rails).

Para cualquier forma que requiera la carga de archivos, establecería data-remote="true" y enctype="multipart/form-data" e incluiría rails.js y jquery.iframe-transport.js.

Configuración data-remote="true" con rails.js permite enlazar a ajax:success y crea el modelo Backbone.js en caso de éxito.

HTML:

<form action="/posts.js" method="post" data-remote="true" enctype="multipart/form-data"> 
    <input type="text" name="post[message]" /> 
    <input type="file" name="post[file]" /> 
    <button>Submit</button> 
</form> 

JavaScript:

Es obvio que debe unirse ajax:error para manejar los casos de error.

Para mí, los datos son desinfectados en el modelo ActiveRecord, por lo que no tiene que preocuparse demasiado acerca de la declaración eval.

$('form').bind('ajax:success', function(event, data) { 
    new Model(eval(data)); // Your newly created Backbone.js model 
}); 

rieles controlador:

class PostsController < ApplicationController 
    respond_to :js 

    def create 
    @post = Post.create(params[:post]) 
    respond_with @post 
    end 
end 

Rieles (Ver create.js.haml):

Usando la gema remotipart.

Esto tratar el caso en la forma que hace la carga de archivos con el que se establece enctype, y no cuando lo hace.

Puede elegir llamar al sanitize en su respuesta aquí.

= remotipart_response do 
    - if remotipart_submitted? 
    = "eval(#{Yajl::Encoder.encode(@post)});" 
    - else 
    =raw "eval(#{Yajl::Encoder.encode(@post)});" 
+0

aseado. Dos preguntas sin embargo. En tu controlador, ¿pretendes hacer 'Post.new (params [: post])' o quisiste decir 'Post.create (params [: post])'? Y segundo, ¿dónde colocarías la devolución de llamada '$ ('form'). Bind ('ajax: success')', en una clase Backbone.View para la forma dada? ¡Gracias! –

+0

Gran captura, error tipográfico de mi parte. Debería ser 'Post.create'. Colocaría $ ('form'). Bind ('ajax: success') en mi vista Backbone que representa el formulario. –

+0

Agregue data-type = "json" al formulario y puede quitar la vista. – maletor

0

Creo que no entiende cómo funciona la red troncal. Backbone es una biblioteca MVC para javascript, no un servidor web. Las cargas de archivos se negocian entre el navegador del cliente y su servidor. Backbone es solo la capa intermedia que le ayuda a organizar y presentar datos de una manera fácil y conveniente.

Una vez dicho esto, lo que necesita hacer para asociar un archivo con su modelo es 1) manejar la carga con rieles y luego 2) almacenar el nombre y la ubicación del archivo en una cadena dentro de su modelo.

Así que aquí es la parte de carga de archivos:

http://khamsouk.souvanlasy.com/articles/ajax-file-uploads-in-rails-using-attachment_fu-and-responds_to_parent

Una vez que regrese el objeto list_item, sólo crearía un nuevo campo en su modelo y almacenar list_item.filename y asset_path(list_item).

Espero que ayude.

+0

Además, aquí hay un enlace a una pregunta similar SO de Django http://stackoverflow.com/questions/6092596/backbone-js-link-file -to-model – Swift

3

Es posible que desee comprobar el jquery.iframe.transport plugin. Si está utilizando rails 3, puede usar remotipart en su lugar (incluye el plugin iframe.transport), que se engancha en el controlador ujs de rails para agregar automáticamente soporte para carga de archivos en solicitudes ajax.

+0

Gracias Matt. Terminé usando exactamente lo que describiste hace un tiempo, pero no pude actualizar esta pregunta. –

0

Si no le importa romper la compatibilidad hacia atrás, usted puede tomar ventaja de XHR2 and FormData

Es tan simple como eso:

var data = new FormData($('form.someForm').get(0)); 
$.ajax('http://*****.com', { 
    type:'POST', 
    data: data, 
    processData: false, 
    contentType: false // it automaticly sets multipart/form-data; boundary=... 
}); 
1

Resurrecting éste.

Como se mencionó en las respuestas anteriores, una solicitud multipart/form-data se puede ejecutar a través de jQuery.ajax:

var formData = new FormData(); 
var input = document.getElementById('file'); 

formData.append('file', input.files[0]); 

$.ajax({ 
    url: 'path/to/upload/endpoint' 
    type:'POST', 
    data: formData, 
    processData: false, 
    contentType: false 
}); 

También es importante señalar que, fuera de la caja, Backbone.sync se fusionarán cualquier opciones a través de model.save(null, { /* options here */ }) con las instrucciones $.ajax.

Su guardar procedimiento sería algo como:

var model = new Model({ 
    key: 'value' 
}); 
var input = document.getElementById('file'); 
var formData = new FormData(); 

_.each(model.keys(), function (key) { // Append your attributes 
    formData.append(key, model.get(key)); 
}); 

formData.append('file', input.files[0]); // Append your file 

model.save(null, { 
    data: formData, 
    processData: false, 
    contentType: false 
});