在Rails 3应用程序中添加特定于页面的JavaScript的最佳方法?

时间:2010-08-09 05:42:35

标签: javascript ruby-on-rails ruby-on-rails-3

Rails 3有一些不显眼的JavaScript,非常酷。

但我想知道最好的方法是为特定页面添加额外的JavaScript。

例如,我之前可能做过的事情:

<%= f.radio_button :rating, 'positive', :onclick => "$('some_div').show();" %>

我们现在可以用

之类的东西使其不引人注目
<%= f.radio_button :rating, 'positive' %>

# then in some other file
$('user_rating_positive').click(function() {
  $('some_div').show();
}

所以我想我的问题是在哪里/如何包含JavaScript?我不想填写application.js文件,因为此JavaScript仅适用于此视图。我应该以某种方式为每个页面包含一个自定义JavaScript文件,还是将其粘贴到标题所查找的实例变量中?

10 个答案:

答案 0 :(得分:149)

我想要做的是在content_for :head块中包含每个视图的Javascript,然后在应用程序布局中包含yield到该块。例如

如果它很短,那么:

<% content_for :head do %>
  <script type="text/javascript">
    $(function() {
      $('user_rating_positve').click(function() {
        $('some_div').show();
      }
    });
  </script>
<% end %>

或者,如果更长,那么:

<% content_for :head do %>
  <script type="text/javascript">
    <%= render :partial => "my_view_javascript"
  </script>
<% end %>

然后,在您的布局文件中

<head>
  ...
  <%= yield :head %>
</head>

答案 1 :(得分:102)

如果你想在一个页面上包含javascript,你当然可以将它包含在页面中,但是如果你想对你的javascript进行分组并利用资产管道,缩小js等,那么就可以这样做并且具有额外的js资产,这些资产被组合并且仅在特定页面上加载,通过将js分成仅适用于站点的某些控制器/视图/部分的组。

将资产中的js移动到文件夹中,每个文件夹都有一个单独的清单文件,因此如果您有一个仅在后端使用的管理js库,您可以这样做:

  • 资产
    • Javascript角
      • 管理员
        • ... JS
      • admin.js(管理员组的清单)
      • application.js(应用程序全局组的清单)
      • 全球
        • ... JS

在现有的application.js

//= require jquery
//= require jquery_ujs
//= require_tree ./global // requires all js files in global folder

在新的admin.js清单文件中

//= require_tree ./admin // requires all js files in admin folder

通过编辑config / production.rb

确保加载了这个新的js清单
config.assets.precompile += %w( admin.js )

然后调整页面布局,以便为页面头部添加一些额外的j:

<%= content_for :header %>   

然后在想要包含此特定js组(以及普通应用程序组)和/或任何特定于页面的js,css等的视图中:

<% content_for :header do %>
  <%= javascript_include_tag 'admin' %>  
<% end %>

你当然可以用css做同样的事情,并以类似的方式将其分组,仅适用于网站的某些区域。

答案 2 :(得分:12)

我更喜欢以下......

在您的application_helper.rb文件中

def include_javascript (file)
    s = " <script type=\"text/javascript\">" + render(:file => file) + "</script>"
    content_for(:head, raw(s))
end

然后在您的特定视图中(此示例中为app / views / books / index.html.erb)

<% include_javascript 'books/index.js' %>

......似乎对我有用。

答案 3 :(得分:11)

这些答案对我帮助很大!如果有人想再多一点......

  1. 如果您希望将javascripts预编译,则需要将javascripts放入清单中。但是,如果您需要application.js.coffee中的每个javascript文件,那么每次导航到不同的页面时都会加载所有javacsripts,并且打败特定于页面的javascripts的目的将被取消。
  2. 因此,您需要创建自己的清单文件(例如speciifc.js),该文件将需要所有特定于页面的javascript文件。另外,修改require_tree

    中的application.js

    应用/资产/ Javascript角/ application.js中

    //= require jquery
    //= require jquery_ujs
    //= require_tree ./global
    

    应用/资产/ Javascript角/ specific.js

    //= require_tree ./specific
    

    然后在environments/production.rb中使用配置选项

    将此清单添加到预编译列表中

    config.assets.precompile += %w( specific.js )

    完成!应始终加载的所有共享 javascripts将放在app/assets/javascripts/global文件夹中,以及app/assets/javascripts/specific中的页面特定javascripts。您只需从视图中调用特定于页面的javascripts,如

    <%= javascript_include_tag "specific/whatever.js" %> //.js是可选的。

    这已经足够了,但我也希望使用javascript_include_tag params[:controller]。创建控制器时,与{1}}中的其他人一样,会在app/assets/javascripts中生成关联的coffeescript文件。有真正的控制器特定的 javascripts,只有在用户到达特定的控制器视图时才会加载。

    所以我创建了另一个清单controller-specific.js

    应用/资产/ Javascript角/控制器specific.js

    //= require_directory .

    这将包括与控制器关联的所有自动生成的coffeescripts。此外,您需要将其添加到预编译列表。

    config.assets.precompile += %w( specific.js controller-specific.js )

答案 4 :(得分:9)

如果您不想使用资产管道或complex work arounds来获取必要的页面特定的javascript(我同情),这是最简单,最强大的方式,它与上面的答案相同,但与只需使用更少的代码:

<%= javascript_include_tag "my_javascipt_file" %>

注意:对于使用content_for :head

的答案,每个include标记需要多一个http请求

答案 5 :(得分:7)

看一下pluggable_js gem。您可能会发现此解决方案更易于使用。

答案 6 :(得分:3)

我的理解是,资产管道旨在通过将所有js混合到一个(缩小的)文件中来减少页面加载时间。虽然表面看起来似乎令人反感,但它实际上已经存在于C和Ruby等流行语言中。诸如“包含”标记之类的东西旨在防止多个文件包含,并帮助程序员组织他们的代码。当您在C中编写和编译程序时,所有代码都存在于正在运行的程序的每个部分中,但是只有在使用该代码时才将方法加载到内存中。从某种意义上说,编译的程序不包含任何东西来保证代码很好地模块化。我们通过以这种方式编写程序来使代码模块化,并且操作系统仅将给定位置所需的对象和方法加载到内存中。甚至还有“特定方法包含”这样的东西吗?如果你的rails应用程序很安静,那么这基本上就是你所要求的。

如果你编写javascript以便它增加页面上HTML元素的行为,那么这些函数是设计上的“页面特定的”。如果您编写的某些复杂代码无论其上下文如何都会执行,那么可以考虑将该代码绑定到html元素(您可以使用body标签,如Garber-Irish method中所述) 。如果函数有条件地执行,则性能可能会小于所有这些额外的脚本标记。

我正在考虑使用paloma gem,如rails apps project中所述。然后,您可以通过在paloma回调中包含特定于页面的函数来使您的javascript页面特定:

Paloma.callbacks['users']['new'] = function(params){
    // This will only run after executing users/new action
    alert('Hello New Sexy User');
}; 

你使用rails,所以我知道你喜欢宝石:)

答案 7 :(得分:3)

您不应该在资产管道之外加载JS或CSS文件,因为您失去了使Rails如此出色的重要功能。而且你不需要另一个宝石。我相信使用尽可能少的宝石,这里不需要使用宝石。

你想要的是“控制器特定的Javascript”(“底部包含特定于操作的Javascript”。)这允许你为特定的CONTROLLER加载一个特定的JavaScript文件。试图将你的Javascript连接到一个视图是善良的...向后并且不遵循MVC设计模式。您希望将其与控制器或控制器内的操作相关联。

不幸的是,无论出于何种原因,Rails开发人员决定默认情况下,每个页面都会加载位于资产目录中的每个JS文件。为什么他们决定这样做而不是默认启用“Controller Specific Javascript”我永远不会知道。这是通过application.js文件完成的,默认情况下包含以下代码行:

//= require_tree .

这称为指令。这是sprockets用于加载assets / javascripts目录中的每个JS文件的内容。默认情况下,sprockets会自动加载application.js和application.css,而require_tree指令会在各自的目录中加载每个JS和Coffee文件。

注意:当您使用脚手架时(如果您不是脚手架,现在是开始的好时机),Rails会自动为您生成咖啡文件,脚手架的控制器。如果您希望它生成标准JS 文件而不是咖啡文件,请删除<默认情况下启用的咖啡宝石 < strong> Gemfile ,你的脚手架将改为创建JS文件。

好的,启用“Controller Specific Javascript”的第一步是从application.js文件中删除require_tree代码,或者将其更改为assets / javascripts目录中的文件夹仍然需要全局JS文件。即:

//= require_tree ./global

第2步:进入config / initializers / assets.rb文件,添加以下内容:

%w( controllerone controllertwo controllerthree ).each do |controller|
  Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
end

插入所需的控制器名称。

第3步:用此替换application.html.erb文件中的javascript_include_tag(注意参数[:controller]部分:

<%= javascript_include_tag 'application', params[:controller], 'data-turbolinks-track': 'reload' %>

重新启动服务器和中提琴!使用您的脚手架生成的JS文件现在仅在调用该控制器时加载。

需要在控制器中的特定ACTION上加载特定的JS文件,I.E。 / articles / new ?这样做:

application.html.erb

<%= javascript_include_tag "#{controller_name}/#{action_name}" if AppName::Application.assets.find_asset("#{controller_name}/#{action_name}") %>

配置/初始化/ assets.rb

config.assets.precompile += %w(*/*)

然后在assets / javascripts文件夹中添加一个与您的控制器同名的新文件夹,并将您的js文件与您的操作同名。然后它会将其加载到该特定操作上。

答案 8 :(得分:1)

好吧也许这就像是有史以来最糟糕的工作但我创建了一个只渲染出.js文件的控制器方法

控制器

def get_script
   render :file => 'app/assessts/javascripts/' + params[:name] + '.js'
end
def get_page
   @script = '/' + params[:script_name] + '.js?body=1'
   render page
end

查看

%script{:src => @script, :type => "text/javascript"}

如果由于某种原因我们不想这样做,请告诉我。

答案 9 :(得分:1)

添加JS的首选方法是页脚,所以你可以这样做:

<强> show.html.erb:

<% content_for :footer_js do %>
   This content will show up in the footer section
<% end %>

layouts / application.html.erb

<%= yield :footer_js %>