2011-06-28 17 views
29

Używam aplikacji Backbone.js w aplikacji Rails i muszę pobierać pliki w ramach jednego z modeli szkieletu.Przesyłanie plików za pomocą narzędzia Backbone

Nie wierzę, że sieć szkieletowa pozwala na wielostronicowe przesyłanie plików po wyjęciu z pudełka. Czy ktokolwiek zdołał uruchomić go za pomocą wtyczki lub innej biblioteki zewnętrznej? Jak mogę rozszerzyć Backbone.js, aby to wspierać?

Odpowiedz

20

Odpowiadając na moje własne pytanie po kilku miesiącach prób, używając różnych metod. Moje rozwiązanie jest następujące (z Railsami).

Dla jakiejkolwiek formie, która wymaga przesyłania plików Chciałbym ustawić data-remote="true" i enctype="multipart/form-data" i obejmują rails.js i jquery.iframe-transport.js.

Ustawienie z rails.js pozwala mi powiązać z ajax:success i utworzyć model Backbone.js na sukces.

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:

Należy oczywiście wiązać ajax:error obsługiwać przypadki błędów.

Dla mnie dane są odkażane w modelu ActiveRecord, więc nie trzeba się martwić zbytnio o rachunku eval.

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

Szyny Kontroler:

class PostsController < ApplicationController 
    respond_to :js 

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

Szyny View (create.js.haml):

Używanie klejnotu remotipart.

To zajmie się sprawą, gdy formularz będzie ładował pliki z ustawieniem enctype, a gdy nie.

Możesz tu zadzwonić pod numer sanitize w swojej odpowiedzi.

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

Schludny. Jednak dwa pytania. Czy w twoim kontrolerze masz zamiar zrobić "Post.new (params [: post])" lub czy faktycznie masz na myśli 'Post.create (params [: post])'? Po drugie, gdzie można umieścić callback '$ ('form'). Bind ('ajax: success')' w klasie Backbone.View dla danego formularza? Dzięki! –

+0

Świetny połów, literówka z mojej strony. Powinien to być 'Post.create'. Chciałbym umieścić $ ("formularz"). Bind ("ajax: success") w moim widoku kręgosłupa, który renderuje formularz. –

+0

Dodaj data-type = "json" do formularza i możesz usunąć widok. – maletor

0

Myślę, że nie rozumiesz, jak działa szkielet. Backbone jest biblioteką MVC dla javascript, a nie serwera WWW. Przesyłanie plików jest negocjowane między przeglądarką klientów a serwerem. Szkielet to tylko środkowa warstwa, która pomaga w uporządkowaniu i prezentacji danych w łatwy i wygodny sposób.

Zgodnie z tym, co musisz zrobić, aby powiązać plik z modelem, to 1) obsłuż ładowanie z szynami, a następnie 2) zapisz nazwę pliku i lokalizację w ciągu znaków w twoim modelu.

Więc tutaj jest częścią przesyłania plików:

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

Gdy wrócisz obiekt list_item, byś po prostu utworzyć nowe pole w modelu i przechowywać list_item.filename i asset_path(list_item).

Nadzieję, że pomaga.

+0

Również tutaj jest link do podobnego SO pytanie dla Django http://stackoverflow.com/questions/6092596/backbone-js-link-file -to-model – Swift

3

Możesz wypróbować wtyczkę jquery.iframe.transport. Jeśli używasz torów 3, możesz zamiast tego użyć remotipart (zawiera on wtyczkę iframe.transport), która podpina się do sterownika ujs szyny, aby automatycznie dodawać obsługę przesyłania plików w żądaniach ajax.

+0

Dzięki Matt. Skończyło się na używaniu dokładnie tego, co opisałeś chwilę, ale nie udało mi się zaktualizować tego pytania. –

0

Jeśli nie przeszkadza złamać kompatybilności wstecznej, można skorzystać z XHR2 and FormData

To proste:

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 ten jeden.

Jak wspomniano w poprzednich odpowiedziach, żądanie multipart/form-data może być wykonywane poprzez 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 
}); 

Ważne jest również, aby pamiętać, że, out-of-the-box, Backbone.sync scali każdy opcje poprzez model.save(null, { /* options here */ }) z instrukcjami $.ajax.

Twój zapisać procedurę będzie wyglądać następująco:

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 
}); 
Powiązane problemy