Ruby-on-rails Rails 3.1 资产管道:如何加载特定于控制器的脚本?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6571753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 01:31:37  来源:igfitidea点击:

Rails 3.1 asset pipeline: how to load controller-specific scripts?

ruby-on-railsruby-on-rails-3.1asset-pipelineassetssprockets

提问by Mike Bevz

If I generate a new controller in Rails 3.1, also a javascript file with the name of the controller will added automatically. Firstly, I thought this javascript file will used only, when the related controller is called.

如果我在 Rails 3.1 中生成一个新控制器,也会自动添加一个带有控制器名称的 javascript 文件。首先,我认为这个 javascript 文件只会在调用相关控制器时使用。

By default there is the instruction //= require_tree .in the application.js-file, that include every javascript file on it's tree.

默认情况下//= require_tree .application.js-file 中有指令,其中包含其树上的每个 javascript 文件。

How could I load only the controller specific script?

我怎么能只加载控制器特定的脚本?

回答by Nguyen Chien Cong

To load only the necessary name_of_the_js_file.js file:

只加载必要的 name_of_the_js_file.js 文件:

  1. remove the //=require_treefrom application.js

  2. keep your js file (that you want to load when a specific page is loaded) in the asset pipeline

  3. add a helper in application_helper.rb

    def javascript(*files)
      content_for(:head) { javascript_include_tag(*files) }
    end
    
  4. yield into your layout:

    <%= yield(:head) %>
    
  5. add this in your view file:

    <% javascript 'name_of_the_js_file' %>
    
  1. 除去//=require_treeapplication.js

  2. 将您的 js 文件(您希望在加载特定页面时加载)保留在资产管道中

  3. 添加一个助手 application_helper.rb

    def javascript(*files)
      content_for(:head) { javascript_include_tag(*files) }
    end
    
  4. 屈服于您的布局:

    <%= yield(:head) %>
    
  5. 在您的视图文件中添加:

    <% javascript 'name_of_the_js_file' %>
    

Then it should be ok

那么应该没问题

回答by albandiguer

An elegant solution for this is to require controller_name in your javascript_include_tag

一个优雅的解决方案是在你的 javascript_include_tag 中要求 controller_name

see http://apidock.com/rails/ActionController/Metal/controller_name/class

http://apidock.com/rails/ActionController/Metal/controller_name/class

<%= javascript_include_tag "application", controller_name %>

controller_name.js will be loaded and is in the asset also, so you can require other files from here.

controller_name.js 将被加载并且也在资产中,所以你可以从这里获取其他文件。

Example, rendering cars#index will give

例如,渲染汽车#index 将给出

<%= javascript_include_tag "application", "cars" %>

where cars.js can contain

car.js 可以包含的地方

//= require wheel
//= require tyre

Enjoy !

享受 !

回答by Le Duc Duy

I always include this inside my layout files. It can scope your js to action

我总是将它包含在我的布局文件中。它可以将您的 js 范围限定为行动

<%= javascript_include_tag params[:controller] if AppName::Application.assets.find_asset("#{params[:controller]}.js") %>
<%= javascript_include_tag "#{params[:controller]}_#{params[:action]}"  if AppName::Application.assets.find_asset("#{params[:controller]}_#{params[:action]}.js") %>

回答by Robin

Your problem can be solved in different ways.

您的问题可以通过不同的方式解决。

Add the assets dynamically

动态添加资产

Please consider that this isn't a good solution for the production mode, because your controller specifics won't be precompiled!

请考虑这对于生产模式来说不是一个好的解决方案,因为您的控制器细节不会被预编译!

  1. Add to our application helper the following method:

    module ApplicationHelper
        def include_related_asset(asset)
        #          v-----{Change this}
            if !YourApp::Application.assets.find_asset(asset).nil?
                case asset.split('.')[-1]
                    when 'js'
                        javascript_include_tag asset
                    when 'css'
                        stylesheet_link_tag asset
                end
            end
        end
    end
    
  2. Call the helper method in your layout-file:

    <%= include_related_asset(params[:controller].to_param + '_' + params[:action].to_param . 'js') %>
    
  3. Create specific assets for your controller actions. E. g. controller_action.js

  1. 将以下方法添加到我们的应用程序助手中:

    module ApplicationHelper
        def include_related_asset(asset)
        #          v-----{Change this}
            if !YourApp::Application.assets.find_asset(asset).nil?
                case asset.split('.')[-1]
                    when 'js'
                        javascript_include_tag asset
                    when 'css'
                        stylesheet_link_tag asset
                end
            end
        end
    end
    
  2. 在您的layout-file 中调用 helper 方法:

    <%= include_related_asset(params[:controller].to_param + '_' + params[:action].to_param . 'js') %>
    
  3. 为您的控制器操作创建特定资产。例如controller_action.js

Please don't forget to change YourAppto the name of your app.

请不要忘记更改YourApp为您的应用程序名称。

Use yield

yield

  1. Add <%= yield :head%>to your layout head
  2. Include your assets from your action views:

    <% content_for :head do %>
    <%= javascript_include_tag 'controller_action' %>
    <% end %>
    
  1. 添加<%= yield :head%>到您的布局头
  2. 从您的操作视图中包含您的资产:

    <% content_for :head do %>
    <%= javascript_include_tag 'controller_action' %>
    <% end %>
    

Please see the Rails guidesfor further information.

有关更多信息,请参阅Rails 指南

回答by 6ft Dan

I like albandiguer's solution. With which I've found that javascript/coffeescript assets are not individually precompiled. Which causes all sorts of errors trying to use javascript_path. I'll share my solution to that problem after I address an issue a few people mentioned in his comments. Mainly dealing with only a partial set of controller named JavaScript files.

我喜欢albandiguer 的解决方案。我发现 javascript/coffeescript 资产不是单独预编译的。这会导致尝试使用javascript_path. 在解决了几个人在他的评论中提到的问题后,我将分享我对该问题的解决方案。主要只处理一部分名为 JavaScript 文件的控制器。

So I built an application helper to detect if the file exists in the javascript directory regardless of .coffee/.js extension:

因此,我构建了一个应用程序助手来检测 javascript 目录中是否存在该文件,而不管 .coffee/.js 扩展名如何:

module ApplicationHelper
  def javascript_asset_path(basename)
    Sprockets::Rails::Helper.assets.paths.select{|i|
      i =~ /javascript/ and i =~ /#{Rails.root}/
    }.each do |directory|
      if Dir.entries(directory).map {|i| i.split('.')[0]}.compact.
          include? basename
        return File.join(directory, basename)
      end
    end
    nil
  end
end

This method will return the full path to the javascript file if it exists. Otherwise it returns nil. So following Pencilcheck's comment you can add this method for a conditional include:

如果存在,此方法将返回 javascript 文件的完整路径。否则返回零。因此,按照 Pencilcheck 的评论,您可以为条件包含添加此方法:

<%= javascript_include_tag(controller_name) if javascript_asset_path(controller_name) %>

And now you have a proper conditional include. Now for the issue of precompiled assets. Generally for optimization you don't want assets precompiledindividually. You can however do it if you must:

现在你有了一个合适的条件包含。现在关于预编译资产的问题。通常为了优化,您不希望单独预编译资产。但是,如果您必须这样做,您可以:

# Live Compilation
config.assets.compile = true

You can add this do your environment config file. Test it in your development environment file first. Again this is ill-advisable. The Rails asset pipeline uses Sprockets to optimize everything:

你可以添加这个做你的环境配置文件。首先在您的开发环境文件中测试它。这再次是不明智的。Rails 资产管道使用链轮优化一切:

Sprockets loads the files specified, processes them if necessary, concatenates them into one single file and then compresses them (if Rails.application.config.assets.compress is true). By serving one file rather than many, the load time of pages can be greatly reduced because the browser makes fewer requests. Compression also reduces file size, enabling the browser to download them faster.

Sprockets 加载指定的文件,必要时处理它们,将它们连接成一个文件,然后压缩它们(如果 Rails.application.config.assets.compress 为 true)。通过提供一个文件而不是多个文件,页面的加载时间可以大大减少,因为浏览器发出的请求更少。压缩还可以减小文件大小,使浏览器能够更快地下载它们。

PLEASE READthe documentation for further details of the mechanics of Sprockets (Asset Pipeline) http://guides.rubyonrails.org/asset_pipeline.html

请阅读文档以获取有关链轮(资产管道)机制的更多详细信息http://guides.rubyonrails.org/asset_pipeline.html

Assets aren't precompiled individually. For example when I try:

资产不会单独预编译。例如,当我尝试:

<%= javascript_include_tag 'event' %>

I get:

我得到:

Sprockets::Rails::Helper::AssetFilteredError: Asset filtered out and will not be served: add Rails.application.config.assets.precompile += %w( event.js )to config/initializers/assets.rband restart your server

链轮:: Rails的助手:: :: AssetFilteredError:资产过滤掉,将不送达:添加Rails.application.config.assets.precompile += %w( event.js )config/initializers/assets.rb并重新启动服务器

So you can include which assets to be precompiled individually. We just need to add the relevant controller named javascript files in our asset initializer. Well we can do this programatically.

因此,您可以包含要单独预编译的资产。我们只需要在我们的资产初始值设定项中添加名为 javascript 文件的相关控制器。好吧,我们可以通过编程来做到这一点。

To get a list of controller names I will use ecoologic's example:

要获取控制器名称列表,我将使用ecoologic 的示例

all_controllers =  Dir[
    Rails.root.join('app/controllers/*_controller.rb')
  ].map { |path|
    path.match(/(\w+)_controller.rb/); 
  }.compact

And now to get the name of all javascript files that match the basename of the controller name you can use the following:

现在要获取与控制器名称的基本名称匹配的所有 javascript 文件的名称,您可以使用以下命令:

javascripts_of_controllers = Sprockets::Rails::Helper.assets.paths.select{|a_path|
    a_path =~ /javascript/ and a_path =~ /#{Rails.root}/
  }.map {|a_path|
    Dir.entries(a_path)
  }.flatten.delete_if {|the_file|
    !the_file['.js']
  }.collect {|the_file|
    the_file if all_controllers.any? {|a_controller| the_file[a_controller]}
  }

Then you can try:

那你可以试试:

# config/initializers/assets.rb
Rails.application.config.assets.precompile += javascripts_of_controllers

This will get you a list of all javascript files, without directory path, that match your controller name. Note if your controller name is plural, the javascript name should be as well. Also note if the controller is singular and the javascript file is plural this will still include it because of the_file[a_controller]will succeed on a partial match.

这将为您提供与您的控制器名称匹配的所有 javascript 文件的列表,没有目录路径。请注意,如果您的控制器名称是复数,那么 javascript 名称也应该是复数。另请注意,如果控制器是单数而 javascript 文件是复数,这仍将包括它,因为the_file[a_controller]在部分匹配时会成功。

Feel free to try this out in your Rails.application.config.assets.precompilesetting. I know that this gets you the list of files correctly. But I'll leave you to test it. Let me know if there are any nuances involved with precompiling this way as I am curious.

随意在您的Rails.application.config.assets.precompile设置中尝试一下。我知道这可以让您正确地获得文件列表。但我会让你测试它。如果我很好奇,请让我知道以这种方式进行预编译是否有任何细微差别。

For a very thorough explanation on how assets precompile see this blog: http://www.sitepoint.com/asset-precompile-works-part/

有关资产如何预编译的非常详尽的解释,请参阅此博客:http: //www.sitepoint.com/asset-precompile-works-part/

回答by ExiRe

I recently found a simple approach to use generated scripts for specific controller. I use for that solution gem gon. Add in a controller:

我最近发现了一种简单的方法来为特定的控制器使用生成的脚本。我用于该解决方案gem gon。添加一个控制器:

class HomesController < ApplicationController
  before_filter :remember_controller

  private

  def remember_controller
    gon.controller = params[:controller]
  end
end

After that open your homes.js.cofeeand add in the beginning of file:

之后打开你的homes.js.cofee并在文件的开头添加:

jQuery ->
  if gon.controller == "sermons"
    # Place all functions here...

That is all.

就这些。