Pipeline cannot return @variables when using ruby ​​coding in .js.erb in Rails

I follow the https://devcenter.heroku.com/articles/direct-to-s3-image-uploads-in-rails#jquery-file-upload-callbacks Tutorial on using s3_direct_upload in a local development environment. There are some javascripts that set the fileupload function for each file field. All this works fine if I just include the codes directly under the form, but it just doesn't work if I put the code in the js.erb file in app/assets/javascripts/ . Mistake:

 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' 

As you can see, line 19 from the above code is used to print @ s3_direct_post.url. It was printed correctly when I included all javascript in the file. If I trace line 14 to s3_direct_upload.js.erb , this is the url line:

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

It seems that for some reason, the javascript file in the assets folder (in the assets pipeline) was compiled separately and therefore the @s3_direct_post that is installed in the Controller is not set here.

Of course, I can always put those in <script> in the viewer file, but it's not very elegant. Is there a way to separate js coding by pages and solve the problem above?

+7
javascript ruby-on-rails asset-pipeline
source share
2 answers

All JS files inside / assets / javascript are part of the asset pipeline. During production, the resource pipeline is compiled in advance when the Rails application is deployed (for example, not for every request). This is why @s3_direct_post.url is zero.

I agree that injecting all of the JS code in a view is less than ideal and not very elegant. I used to come up with approaches based on JS infrastructures such as Google Analytics, where only 2-3 JS lines are placed in HTML:

 /* /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 }) }); 

Then, in the view, you only need to reference the Config API you created:

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

However, if you are really determined not to have JS in the views. You can load configurations through a dynamic JSON request:

 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 

Then you can download all the configs via ajax by requesting /js_configs.json . However, this approach requires a bit more caution due to the asynchronous nature of Ajax. For example, you should be careful not to call JS functions that rely on configurations until an Ajax request is received.

+5
source share

Finally, I will get around this problem by using another s3-related gem: s3_file_field , and it just works well even without heavy setup. Unfortunately, I can’t find all the related information in my research to solve this problem.

I hope this help!

+1
source share

All Articles