简体   繁体   English

在Rails中的.js.erb中使用ruby编码时,资产管道无法返回@variables

[英]Asset pipeline cannot return @variables while using ruby coding in .js.erb in Rails

I am following the https://devcenter.heroku.com/articles/direct-to-s3-image-uploads-in-rails#jquery-file-upload-callbacks Tutorial to use s3_direct_upload on local development environment. 我正在关注https://devcenter.heroku.com/articles/direct-to-s3-image-uploads-in-rails#jquery-file-upload-callbacks教程,以便在本地开发环境中使用s3_direct_upload。 There's some javascripts which set the fileupload function for each file fields. 有一些javascripts为每个文件字段设置fileupload函数。 It all works great if I simply include the codes right below the form, but it just doesn't work if I put the code in a js.erb file under app/assets/javascripts/ . 如果我只是简单地在表单下面包含代码,那么这一切都很有效,但如果我将代码放在app/assets/javascripts/下的js.erb文件中,它就行不通。 The error is: 错误是:

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 may see, line 19 from the above code is used to print out the @s3_direct_post.url. 如您所见,上面代码中的line 19用于打印出@ s3_direct_post.url。 It was correctly printed when I include all the javascript in the file. 当我在文件中包含所有javascript时,它被正确打印。 If I trace the line 14 in the s3_direct_upload.js.erb , it is the url line: 如果我跟踪s3_direct_upload.js.erb的第14行,那么它是url行:

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

It seems like that for some reason, the javascript file under the assets folder (in the asset pipeline) is compiled separately and so @s3_direct_post , which is set in the Controller is not set here. 看起来由于某种原因, assets文件夹(在资产管道中)下的javascript文件是单独编译的,因此在此处未设置在Controller中设置的@s3_direct_post

Of course I can always put those in <script> at the viewer file but it is not quite elegant. 当然,我总是可以把它们放在查看器文件中的<script>中,但它不是很优雅。 Is there any way to separate page-specific js coding and solve the problem above? 有没有办法分离页面特定的js编码和解决上面的问题?

All JS files within /assets/javascript are part of the asset pipeline. / assets / javascript中的所有JS文件都是资产管道的一部分。 In production the asset pipeline is compiled beforehand when your Rails app is deployed (eg not on each request). 在生产中,在部署Rails应用程序时预先编译资产管道(例如,不在每个请求上)。 This is why @s3_direct_post.url is nil. 这就是@s3_direct_post.url为零的原因。

I agree that injecting the whole JS code in the view is less than ideal and not very elegant. 我同意在视图中注入整个JS代码并不理想,也不是很优雅。 In the past I have come up with approaches that take inspiration from JS frameworks like Google Analytics, where only 2-3 lines of JS are placed in the HTML: 在过去,我提出了从Google Analytics等JS框架中获取灵感的方法,其中只有2-3行JS放在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 the view only needs to reference the Config API you've created: 然后视图只需要引用您创建的Config API:

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

However if you're really determined not to have any JS in the views. 但是如果你真的决定不在视图中有任何JS。 You could load the configs via a dynamic JSON request: 您可以通过动态JSON请求加载配置:

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 load all the configs via ajax by requesting /js_configs.json . 然后,您可以通过请求/js_configs.json通过ajax加载所有配置。 However this approach requires a bit more care due to the asynchronous nature of Ajax. 但是,由于Ajax的异步特性,这种方法需要更加小心。 Eg you have to be careful to not call JS functions that rely on configs until the Ajax request has finished being retrieved. 例如,在Ajax请求完成检索之前,您必须小心不要调用依赖于配置的JS函数。

finally I work around this problem by using another s3 related gem: s3_file_field and it just works well even without heavy tweaking. 最后我通过使用另一个s3相关的gem解决了这个问题: s3_file_field ,即使没有大量调整也能正常工作。 unfortunately I can't find all related information through my study on solving this problem. 遗憾的是,通过我的研究解决这个问题,我无法找到所有相关信息。

I hope this help! 我希望这有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM