File upload with Backbone
I'm using Backbone.js in a Rails app and I need to do file uploads as part of one of the Backbone models.
I don't believe Backbone allows for multi-part file upload out of the box. Has anyone managed to get it working via some plugin or with another external lib? How can I extend Backbone.js to开发者_JAVA百科 support this?
Answering my own question after few months of trial using different methods. My solution is the following (with Rails).
For any form that requires file upload I would set data-remote="true"
and enctype="multipart/form-data"
and include rails.js and jquery.iframe-transport.js.
Setting data-remote="true"
with rails.js allows me to bind to ajax:success
and create the Backbone.js model on success.
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:
You should obviously bind ajax:error
to handle error cases.
For me, the data is sanitized in the ActiveRecord
model, so don't have to worry too much about the eval
statement.
$('form').bind('ajax:success', function(event, data) {
new Model(eval(data)); // Your newly created Backbone.js model
});
Rails Controller:
class PostsController < ApplicationController
respond_to :js
def create
@post = Post.create(params[:post])
respond_with @post
end
end
Rails View (create.js.haml):
Using the remotipart gem.
This will handle the case when the form does file uploads with enctype
being set, and when it doesn't.
You could choose to call sanitize
on your response here.
= remotipart_response do
- if remotipart_submitted?
= "eval(#{Yajl::Encoder.encode(@post)});"
- else
=raw "eval(#{Yajl::Encoder.encode(@post)});"
You may want to check out the jquery.iframe.transport plugin. If you're using rails 3, you can use remotipart instead (it bundles the iframe.transport plugin), which hooks into rails's ujs driver to automatically add support for file upload in ajax requests.
Resurrecting this one.
As mentioned in previous answers, a multipart/form-data request can be executed via 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
});
It is also important to note that, out-of-the-box, Backbone.sync
will merge any options via model.save(null, { /* options here */ })
with the $.ajax
instructions.
Your save procedure would look something like:
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
});
I think you're misunderstanding how backbone works. Backbone is an MVC library for javascript, not a web server. File uploads are negotiated between the clients browser and your server. Backbone is just the middle layer that helps you organize and present data in an easy, convenient manner.
That being said, what you need to do to associate a file with your model is 1) handle the upload with rails and then 2) store the file name and location in a string within your model.
So here's the file uploading part:
http://khamsouk.souvanlasy.com/articles/ajax-file-uploads-in-rails-using-attachment_fu-and-responds_to_parent
Once you get back the list_item object, you would just create a new field in your model and store list_item.filename
and asset_path(list_item)
.
Hope that helps.
If you don't mind to break backward compatibility, you can take advantage of XHR2 and FormData
It's simple as that:
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=...
});
精彩评论