2014-07-16 6 views
7

Ich befolge das Tutorial https://devcenter.heroku.com/articles/direct-to-s3-image-uploads-in-rails#jquery-file-upload-callbacks, um s3_direct_upload für die lokale Entwicklungsumgebung zu verwenden. Es gibt einige Javascripts, die die Dateiuploadfunktion für jede Dateifelder festlegen. Alles funktioniert gut, wenn ich einfach die Codes direkt unter dem Formular einfüge, aber es funktioniert einfach nicht, wenn ich den Code in eine js.erb-Datei unter app/assets/javascripts/ einfüge. Der Fehler ist:Asset-Pipeline kann @ variables nicht zurückgeben, während die Ruby-Codierung in .js.erb in Rails verwendet wird

ActionView::Template::Error (undefined method `url' for nil:NilClass 
    (in /s3_direct_upload_gem_test/app/assets/javascripts/s3_direct_upload.js.erb)): 
    18: 
    19: <%= @s3_direct_post.url %> 
    20: 
    21: <%= javascript_include_tag :s3_direct_upload %> 
    app/assets/javascripts/s3_direct_upload.js.erb:14:in `block in singleton class' 

Wie Sie sehen können, line 19 aus dem obigen Code verwendet wird, aus dem @ s3_direct_post.url zu drucken. Es wurde korrekt gedruckt, wenn ich das gesamte Javascript in die Datei einfüge. Wenn ich die Linie 14 in der s3_direct_upload.js.erb verfolgen, ist es die url Linie:

fileInput.fileupload({ 
    fileInput:  fileInput, 
    url:    '<%= @s3_direct_post.url %>', 
    type:   'POST', 
    autoUpload:  true, 
    formData:   <%= @s3_direct_post.fields.to_json.html_safe %>, 

Es ist wie es aus irgendeinem Grund scheint, die JavaScript-Datei unter dem assets Ordner (in der Asset-Pipeline) separat kompiliert und so @s3_direct_post , die in der Controller eingestellt ist, wird hier nicht eingestellt.

Natürlich kann ich diese in <script> immer an der Viewer-Datei setzen, aber es ist nicht ganz elegant. Gibt es eine Möglichkeit, die seitenspezifische js-Codierung zu trennen und das obige Problem zu lösen?

+0

könnten Sie die Zeile '<% p self.class%>' vor dem Fehler einfügen? –

Antwort

5

Alle JS-Dateien in/assets/javascript sind Teil der Asset-Pipeline. In der Produktion wird die Asset-Pipeline im Vorfeld kompiliert, wenn Ihre Rails-App bereitgestellt wird (z. B. nicht bei jeder Anfrage). Deshalb ist @s3_direct_post.url Null.

Ich stimme zu, dass die Injektion des gesamten JS-Codes in der Ansicht weniger als ideal und nicht sehr elegant ist. In der Vergangenheit habe ich mit Ansätzen kommen, die Inspiration nehmen von JS Frameworks wie Google Analytics, wo nur 2-3 Zeilen von JS in der HTML platziert:

/* /assets/javascripts/s3_direct_upload.js */ 
window.MyApp = {}; 
window.MyApp.config = {}; 

window.MyApp.config.getS3Url = function() { 
    if(typeof(window.MyApp.config._s3Url) == ‘undefined’) { 
    throw “No S3 URL configured”; 
    } 
    return window.MyApp.config._s3Url; 
}; 

window.MyApp.config.setS3Url = function(url) { 
    window.MyApp.config._s3Url = url; 
} 

// ... 
$('#upload-button').on('click', function(){ 
    fileInput.fileupload({ 
    fileInput:  fileInput, 
    url:    window.MyApp.config.getS3Url(), 
    type:   'POST', 
    autoUpload:  true 
    }) 
}); 

Dann nur die Ansicht muss die Config-API referenzieren Sie haben erstellt:

<script type=“text/javascript”> 
    window.MyApp.config.setS3Url('<%= @s3_direct_post.url %>'); 
</script> 

Allerdings, wenn Sie wirklich entschlossen sind, keine JS in den Ansichten zu haben. Sie könnten die configs über eine dynamische JSON Anfrage laden:

class JSConfigsController < ApplicationController 
    def index 
    configs = { 
     's3URl' => @s3_direct_post.url 
     # etc 
    } 

    respond_to do |f| 
     f.json do 
     render json: {config: configs} # => {"config": {"s3Url": "http://the_url"}} 
     end 
    end 
    end 
end 

Dann können Sie alle configs über Ajax laden, indem /js_configs.json anfordert. Dieser Ansatz erfordert jedoch wegen der asynchronen Natur von Ajax etwas mehr Sorgfalt. ZB müssen Sie darauf achten, dass Sie keine JS-Funktionen aufrufen, die auf Configs angewiesen sind, bis die Ajax-Anfrage beendet ist.

+0

Solch eine großartige Antwort. Vielen Dank! – bezzoon

1

schließlich um dieses Problem zu arbeiten, indem ich einen anderen s3 verwandten Edelstein: s3_file_field und es funktioniert einfach gut, auch ohne schwere Feinabstimmung. Leider kann ich durch meine Studie zur Lösung dieses Problems nicht alle relevanten Informationen finden.

Ich hoffe diese Hilfe!