【发布时间】:2011-06-28 00:18:27
【问题描述】:
我在 Rails 应用程序中使用 Backbone.js,我需要将文件上传作为其中一个 Backbone 模型的一部分。
我不相信 Backbone 允许开箱即用的多部分文件上传。有没有人设法通过一些插件或另一个外部库让它工作?如何扩展 Backbone.js 以支持此功能?
【问题讨论】:
标签: javascript ruby-on-rails backbone.js
我在 Rails 应用程序中使用 Backbone.js,我需要将文件上传作为其中一个 Backbone 模型的一部分。
我不相信 Backbone 允许开箱即用的多部分文件上传。有没有人设法通过一些插件或另一个外部库让它工作?如何扩展 Backbone.js 以支持此功能?
【问题讨论】:
标签: javascript ruby-on-rails backbone.js
经过几个月的尝试,使用不同的方法回答了我自己的问题。我的解决方案如下(使用 Rails)。
对于任何需要上传文件的表单,我会设置data-remote="true" 和enctype="multipart/form-data" 并包括rails.js 和jquery.iframe-transport.js。
设置data-remote="true" 和rails.js 允许我绑定到ajax:success 并在成功时创建Backbone.js 模型。
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:
你显然应该绑定ajax:error 来处理错误情况。
对我来说,数据在 ActiveRecord 模型中进行了清理,所以不必太担心 eval 语句。
$('form').bind('ajax:success', function(event, data) {
new Model(eval(data)); // Your newly created Backbone.js model
});
Rails 控制器:
class PostsController < ApplicationController
respond_to :js
def create
@post = Post.create(params[:post])
respond_with @post
end
end
Rails 视图(create.js.haml):
使用remotipart gem。
这将处理表单在设置了enctype 的情况下上传文件的情况,以及没有设置的情况。
您可以在此处选择致电sanitize 回复您的回复。
= remotipart_response do
- if remotipart_submitted?
= "eval(#{Yajl::Encoder.encode(@post)});"
- else
=raw "eval(#{Yajl::Encoder.encode(@post)});"
【讨论】:
Post.new(params[:post]) 还是实际上是指Post.create(params[:post])?其次,您会将$('form').bind('ajax:success') 回调放在给定表单的Backbone.View 类中的什么位置?谢谢!
Post.create。我会将 $('form').bind('ajax:success') 放在呈现表单的 Backbone 视图中。
您可能想查看jquery.iframe.transport 插件。如果您使用的是 rails 3,则可以改用 remotipart(它捆绑了 iframe.transport 插件),它与 rails 的 ujs 驱动程序挂钩,以自动添加对 ajax 请求中文件上传的支持。
【讨论】:
复活这个。
如前面的回答中提到的,multipart/form-data 请求可以通过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
});
还需要注意的是,开箱即用的Backbone.sync 将通过model.save(null, { /* options here */ }) 与$.ajax 指令合并任何选项。
您的保存过程如下所示:
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
});
【讨论】:
我认为您误解了主干的工作原理。 Backbone 是一个用于 javascript 的 MVC 库,而不是一个 Web 服务器。文件上传是在客户端浏览器和您的服务器之间协商的。 Backbone 只是帮助您以简单方便的方式组织和呈现数据的中间层。
话虽如此,将文件与模型关联起来需要做的是 1) 使用 rails 处理上传,然后 2) 将文件名和位置存储在模型中的字符串中。
所以这里是文件上传部分:
一旦您取回 list_item 对象,您只需在模型中创建一个新字段并存储 list_item.filename 和 asset_path(list_item)。
希望对您有所帮助。
【讨论】:
如果您不介意破坏向后兼容性,可以利用XHR2 and FormData
就这么简单:
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=...
});
【讨论】: