Загрузка файла с помощью базовой линии
Я использую Backbone.js в приложении Rails, и мне нужно делать загрузку файлов как часть одной из моделей Backbone.
Я не считаю, что Backbone позволяет загружать многокомпонентные файлы из коробки. Кто-нибудь смог заставить его работать через какой-либо плагин или с другой внешней библиотекой? Как я могу расширить Backbone.js для поддержки этого?
Ответы
Ответ 1
Отвечая на мой собственный вопрос после нескольких месяцев испытаний, используя разные методы. Мое решение следующее (с 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 View (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)});"
Ответ 2
Вы можете проверить плагин jquery.iframe.transport. Если вы используете рельсы 3, вы можете вместо этого использовать remotipart (он связывает плагин iframe.transport), который подключается к рельсам ujs driver автоматически добавлять поддержку для загрузки файлов в запросы ajax.
Ответ 3
Я думаю, вы неправильно понимаете, как работает позвоночник. Backbone - это библиотека MVC для javascript, а не веб-сервер. Загрузка файлов согласовывается между браузером клиентов и вашим сервером. Магистраль - это только средний слой, который помогает вам легко и удобно организовывать и представлять данные.
При этом вам нужно связать файл с вашей моделью: 1) обработать загрузку с помощью рельсов, а затем 2) сохранить имя и местоположение файла в строке в вашей модели.
Итак, вот часть загрузки файла:
http://khamsouk.souvanlasy.com/articles/ajax-file-uploads-in-rails-using-attachment_fu-and-responds_to_parent
Как только вы вернете объект list_item, вы просто создадите новое поле в своей модели и сохраните list_item.filename
и asset_path(list_item)
.
Надеюсь, что это поможет.
Ответ 4
Если вы не возражаете отказаться от обратной совместимости, вы можете воспользоваться XHR2 и 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=...
});
Ответ 5
Возобновление этого.
Как упоминалось в предыдущих ответах, запрос 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
});