Rails 3.1 Asset Pipeline:如何加载特定于控制器的脚本?


76

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

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

如何仅加载控制器特定的脚本?


3
这样做可能不是一个好主意。请参阅答案此相关的问题:stackoverflow.com/questions/8250951/...
gdelfino

1
编写您的JavaScript,使其针对特定页面,然后不必担心所有内容都混在一起的事实。如果这是经过编译的代码,那就是您要做的,对吧?
Ziggy

Answers:


122

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

  1. //=require_tree从中删除application.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' %>
    

那应该没关系


2
值得注意的是,这种方法在生产中效果很好。例如,如果您查看生产中的源代码,您将看到单个控制器javascript文件获得了适当的缓存清除名称,就像主application.js文件一样:<script src =“ / assets / mycontroller-923cef714b82e7dec46117f9aab7fb2c.js” type =“ text / javascript”> </ script>
cailinanne

是的,因为文件本身在资产管道中。我们只是不希望在application.js中需要它。
Nguyen Chien Cong

1
你可以说得更详细点吗?也许我可以帮忙。
阮建聪

13
确保config/application.rb像这样添加一行,config.assets.precompile += %w(name_of_js_file.js)否则可能会像我一样遇到预编译问题。又见jalada.co.uk/2012/01/23/...
ZMorek

1
在Rails 3.2.3中为我工作(需要上面的ZMorek指定的config.assets.precompile选项)
Tatiana Tyu 2012年

83

一个很好的解决方案是在您的javascript_include_tag中要求controller_name

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

<%= javascript_include_tag "application", controller_name %>

controller_name.js也将被加载并且也位于资产中,因此您可以从此处要求其他文件。

例如,渲染cars#index将给出

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

cars.js可以包含的位置

//= require wheel
//= require tyre

请享用 !


虽然在阅读后很明显,但解决方案并未立即出现在我身上。
安德鲁·伯恩斯

11
如果没有每个文件,则controller_name.js可能会遇到一些预编译问题和高速缓存未命中的情况,尤其是如果您未明确预编译每个文件的话。
ZMorek

预编译问题由config.assets.precompile设置解决-有关此问题的其他答案,请参见ZMorek的评论。
塔蒂亚娜(Tatiana Tyu)2012年

1
更好:<%= javascript_include_tag控制器名称,如果asset_path(controller_name)%> <%= stylesheet_link_tag控制器名称,媒体:“ all”,如果asset_path(controller_name)%>
Pencilcheck

1
@Pencilcheck您的解决方案无效。asset_path即使文件不存在,也总是返回路径
Alter Lagos

28

我总是将此包含在布局文件中。它可以使您的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") %>

1
尽管我真的很喜欢,但它似乎在生产中不起作用。
janosrusiczki 2013年

我认为最好的解决方案。
installero


谢谢,请尝试一下。
janosrusiczki

这对我来说是最好的解决方案。它可以在生产中使用。
杰伊

6

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

动态添加资产

请考虑这不是生产模式的好解决方案,因为不会预先编译控制器的详细信息!

  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

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

使用 yield

  1. <%= yield :head%>到布局头
  2. 从操作视图中包括您的资产:

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

请参阅Rails指南以获取更多信息。


3

我喜欢albandiguer的解决方案。通过它,我发现javascript / coffeescript资产没有单独进行预编译。这会导致尝试使用各种错误javascript_path。在我解决了他的评论中提到的几个问题之后,我将分享该问题的解决方案。主要只处理部分名为JavaScript文件的控制器。

因此,我构建了一个应用程序帮助程序,以检测文件是否存在于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

如果存在,此方法将返回javascript文件的完整路径。否则返回nil。因此,在Pencilcheck的注释之后,您可以为条件包括添加此方法:

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

现在您有了适当的条件包含。现在开始发行预编译资产。通常,为了进行优化,您不希望资产单独进行预编译。但是,如果您必须执行以下操作,则可以这样做:

# Live Compilation
config.assets.compile = true

您可以将此添加到您的环境配置文件中。首先在开发环境文件中对其进行测试。同样,这是不明智的。Rails资产管道使用Sprockets优化一切:

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

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

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

<%= javascript_include_tag 'event' %>

我得到:

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

因此,您可以包括要单独预编译的资产。我们只需要在资产初始化程序中添加名为javascript文件的相关控制器即可。好吧,我们可以通过编程方式做到这一点。

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

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

现在,要获取与控制器名称的基本名称匹配的所有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]}
  }

然后,您可以尝试:

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

这将为您提供与您的控制器名称匹配的所有JavaScript文件的列表,不带目录路径。请注意,如果您的控制器名称为复数形式,则javascript名称也应为复数形式。还要注意,如果控制器为单数,并且javascript文件为复数,则由于the_file[a_controller]部分匹配成功,因此仍将包括该控制器。

随时尝试在您的 Rails.application.config.assets.precompile环境中。我知道这可以正确获取文件列表。但是,我会让您进行测试。让我知道,通过这种方式进行预编译是否有任何细微之处,我感到非常好奇。

有关如何预编译资产的非常详尽的说明,请参见以下博客:http : //www.sitepoint.com/asset-precompile-works-part/


我应该在哪里放置all_controllers和javascripts_of_controllers语句?
康斯坦丁·沃罗诺夫

1
好。我把它们都放在资产初始化器(assets.rb)中,但是Sprockets :: Rails :: Helper.assets.paths在这里为空,因此我不得不将其更改为Rails.application.config.assets.paths,其余都很好。非常好的解决方案
Konstantin Voronov 2015年

1

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

class HomesController < ApplicationController
  before_filter :remember_controller

  private

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

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

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

就这些。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.