在 Rails 3 应用程序中添加特定于页面的 JavaScript 的最佳方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3437585/
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
Best way to add page specific JavaScript in a Rails 3 app?
提问by Brian Armstrong
Rails 3 has some unobtrusive JavaScript which is pretty cool.
Rails 3 有一些非常酷的不引人注目的 JavaScript。
But I was wondering what the best way is to include additional JavaScript for a particular page.
但我想知道为特定页面包含额外 JavaScript 的最佳方法是什么。
For example, where I might have previously done:
例如,我以前可能做过的地方:
<%= f.radio_button :rating, 'positive', :onclick => "$('some_div').show();" %>
We can now make it unobtrusive with something like
我们现在可以用类似的东西让它不显眼
<%= f.radio_button :rating, 'positive' %>
# then in some other file
$('user_rating_positive').click(function() {
$('some_div').show();
}
So I guess my question is where/how to include that JavaScript? I don't want to fill up the application.jsfile because this JavaScript is only applicable to this one view. Should I include a custom JavaScript file for each page somehow, or stick it in an instance variable that the header looks for?
所以我想我的问题是在哪里/如何包含该 JavaScript?我不想填满这个application.js文件,因为这个 JavaScript 只适用于这个视图。我应该以某种方式为每个页面包含一个自定义 JavaScript 文件,还是将其粘贴在标题查找的实例变量中?
采纳答案by bjg
What I like to do is include the per-view Javascript in a content_for :headblock and then yieldto that block in your application layout. For example
我喜欢做的是将每个视图的 Javascript 包含在一个content_for :head块中,然后yield在您的应用程序布局中包含该块。例如
If it's pretty short then:
如果它很短,那么:
<% content_for :head do %>
<script type="text/javascript">
$(function() {
$('user_rating_positve').click(function() {
$('some_div').show();
}
});
</script>
<% end %>
or, if longer, then:
或者,如果更长,那么:
<% content_for :head do %>
<script type="text/javascript">
<%= render :partial => "my_view_javascript"
</script>
<% end %>
Then, in your layout file
然后,在您的布局文件中
<head>
...
<%= yield :head %>
</head>
回答by Kenny Grant
If you want to include javascript just on one page, you can include it on the page inline of course, however if you want to group your javascript and take advantage of the asset pipeline, minified js etc, it's possible to do so and have extra js assets which are combined and only loaded on specific pages by splitting your js into groups which only apply in certain controllers/views/sections of the site.
如果您只想在一个页面上包含 javascript,当然可以将其包含在页面内联中,但是如果您想对 javascript 进行分组并利用资产管道、缩小的 js 等,则可以这样做并有额外的通过将您的 js 分成仅适用于站点的某些控制器/视图/部分的组来组合并仅加载到特定页面上的 js 资产。
Move your js in assets into folders, with a separate manifest file for each, so if you had an admin js library that is only used on the backend, you might do this:
将资产中的 js 移动到文件夹中,每个文件夹都有一个单独的清单文件,因此如果您有一个仅在后端使用的管理 js 库,您可以这样做:
- assets
- javascripts
- admin
- ...js
- admin.js (manifest for admin group)
- application.js (manifest for app global group)
- global
- ...js
- admin
- javascripts
- 资产
- javascripts
- 行政
- ....js
- admin.js(管理员组的清单)
- application.js(应用全局组的清单)
- 全球的
- ....js
- 行政
- javascripts
in the existing application.js
在现有的 application.js 中
//= require jquery
//= require jquery_ujs
//= require_tree ./global // requires all js files in global folder
in a new admin.js manifest file
在新的 admin.js 清单文件中
//= require_tree ./admin // requires all js files in admin folder
Make sure this new js manifest is loaded by editing config/production.rb
通过编辑 config/production.rb 确保加载了这个新的 js 清单
config.assets.precompile += %w( admin.js )
Then adjust your page layout so that you can include some extra js for the page head:
然后调整您的页面布局,以便您可以为页面标题包含一些额外的 js:
<%= content_for :header %>
Then in views where you want to include this specific js group (as well as the normal application group) and/or any page-specific js, css etc:
然后在您想要包含此特定 js 组(以及普通应用程序组)和/或任何特定于页面的 js、css 等的视图中:
<% content_for :header do %>
<%= javascript_include_tag 'admin' %>
<% end %>
You can of course do the same thing with css and group it in a similar way for applying only to certain areas of the site.
你当然可以用 css 做同样的事情,并以类似的方式将它分组,以仅应用于网站的某些区域。
回答by Maximus S
These answers helped me a ton! If anyone wants a little more...
这些答案对我帮助很大!如果有人想要多一点...
- You need to put javascripts into manifests if you want them precompiled. However, if you require every javascript file from
application.js.coffeethen all the javacsripts will be loaded every time you navigate to a different page, and the purpose of doing page-specific javascripts will be defeated.
- 如果您希望它们预编译,您需要将 javascripts 放入清单中。但是,如果您需要每个 javascript 文件,
application.js.coffee那么每次导航到不同页面时都会加载所有 javacsript,并且执行特定于页面的 javascript 的目的将落空。
Therefore, you need to create your own manifest file (e.g. speciifc.js) that will require all the page-specific javascript files. Also, modify require_treefrom application.js
因此,您需要创建自己的清单文件(例如speciifc.js),它将需要所有特定于页面的 javascript 文件。另外,修改require_tree自application.js
app/assets/javascripts/application.js
应用程序/资产/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require_tree ./global
app/assets/javascripts/specific.js
应用程序/资产/javascripts/specific.js
//= require_tree ./specific
Then in your environments/production.rbadd this manifest to the precompiled list with the config option,
然后在您environments/production.rb使用 config 选项将此清单添加到预编译列表中,
config.assets.precompile += %w( specific.js )
config.assets.precompile += %w( specific.js )
Done! All the sharedjavascripts that should always be loaded will be placed in app/assets/javascripts/globalfolder, and the page-spcific javascripts in app/assets/javascripts/specific. You can simply call the page-specific javascripts from the view like
完毕!所有应始终加载的共享javascripts 将放在app/assets/javascripts/global文件夹中,而页面特定的 javascripts 在app/assets/javascripts/specific. 您可以简单地从视图中调用特定于页面的 javascripts
<%= javascript_include_tag "specific/whatever.js" %>//.js is optional.
<%= javascript_include_tag "specific/whatever.js" %>//.js 是可选的。
This is sufficient, but I wanted to make a use of javascript_include_tag params[:controller]too. When you create controllers, an associated coffeescript file is generated in app/assets/javascriptslike other people mentioned. There are truly controller-specificjavascripts, which are loaded only when the user reaches the specific controller view.
这已经足够了,但我也想利用它javascript_include_tag params[:controller]。当您创建控制器时,会app/assets/javascripts像其他人提到的那样生成关联的 coffeescript 文件。有真正的控制器特定的javascripts,只有当用户到达特定的控制器视图时才会加载它们。
So I created another manifest controller-specific.js
所以我创建了另一个清单 controller-specific.js
app/assets/javascripts/controller-specific.js
app/assets/javascripts/controller-specific.js
//= require_directory .
//= require_directory .
This will include all the automatically-generated coffeescripts associated with controllers. Also, you need to add it to the precompiled list.
这将包括与控制器关联的所有自动生成的咖啡脚本。此外,您需要将其添加到预编译列表中。
config.assets.precompile += %w( specific.js controller-specific.js )
config.assets.precompile += %w( specific.js controller-specific.js )
回答by cailinanne
I prefer the following...
我更喜欢以下...
In your application_helper.rb file
在您的 application_helper.rb 文件中
def include_javascript (file)
s = " <script type=\"text/javascript\">" + render(:file => file) + "</script>"
content_for(:head, raw(s))
end
and then in your particular view (app/views/books/index.html.erb in this example)
然后在您的特定视图中(在本例中为 app/views/books/index.html.erb)
<% include_javascript 'books/index.js' %>
... seems to work for me.
......似乎对我有用。
回答by AJP
If you don't want to use the asset pipeline or the complex work aroundsto get that necessary page specific javascript (I sympathise), the simplest and most robust way, which achieves the same as the answers above but with less code is just to use:
如果您不想使用资产管道或复杂的变通方法来获得必要的页面特定的 javascript(我同情),最简单和最健壮的方法,它与上面的答案相同,但代码更少,只是为了用:
<%= javascript_include_tag "my_javascipt_file" %>
Note: this does require one more http request per include tag than the answers which use content_for :head
注意:与使用的答案相比,这确实需要每个包含标签多一个 http 请求 content_for :head
回答by peresleguine
Take a look at pluggable_jsgem. You may find this solution easier to use.
看看pluggable_jsgem。您可能会发现此解决方案更易于使用。
回答by Ziggy
My understanding is that the asset pipeline is meant to decrease page load-time by mashing all your js together into one (minified) file. While this may seem repugnant on the surface, it is actually a feature that already exists in popular languages like C and Ruby. Things like "include" tags are meant to prevent multiple inclusion of a file, and to help programmers organize their code. When you write and compile a program in C, all that code is present in every part of your running program, but methods are only loaded into memory when that code is being used. In a sense, a compiled program does not include anything to guarantee that the code is nicely modular. We make the code modular by writing our programs that way, and the operating system only loads into memory the objects and methods we need for a given locality. Is there even such a thing as "method-specific inclusion"? If your rails app is restful, this is essentially what you are asking for.
我的理解是资产管道旨在通过将所有 js 混合到一个(缩小的)文件中来减少页面加载时间。虽然这表面上看起来令人反感,但它实际上是 C 和 Ruby 等流行语言中已经存在的特性。像“include”标签这样的东西是为了防止一个文件被多次包含,并帮助程序员组织他们的代码。当您用 C 编写和编译程序时,所有这些代码都存在于您正在运行的程序的每个部分中,但只有在使用该代码时才将方法加载到内存中。从某种意义上说,编译后的程序不包含任何东西来保证代码很好地模块化。我们通过以这种方式编写我们的程序来使代码模块化,并且操作系统只将我们需要的给定位置的对象和方法加载到内存中。甚至有“特定于方法的包含”这样的东西吗?如果您的 rails 应用程序是安静的,这基本上就是您所要求的。
If you write your javascript so that it augments the behaviour of HTML elements on the page, then those functions are 'page-specific' by design. If there is some complicated code that you wrote in such a way that it will execute regardless of its context, maybe consider binding that code to an html element anyway (you could use the body tag, as described in the Garber-Irish method). If a function executes conditionally, the performance will probably be smaller than all those extra script tags.
如果您编写 javascript 以增强页面上 HTML 元素的行为,那么这些功能在设计上是“特定于页面的”。如果您编写了一些复杂的代码,无论其上下文如何,它都会执行,也许可以考虑将该代码绑定到 html 元素(您可以使用 body 标记,如Garber-Irish 方法中所述)。如果一个函数有条件地执行,其性能可能会小于所有这些额外的脚本标签。
I am thinking of using the palomagem, as described in the rails apps project. Then you can make your javascript page-specific by including page-specific functions in a paloma callback:
我正在考虑使用palomagem,如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');
};
You use rails, so I know you love gems :)
你使用导轨,所以我知道你喜欢宝石 :)
回答by Erick Maynard
You shouldn't be loading your JS or CSS files outside of the asset pipeline because you lose out on important features that make Rails so great. And you don't need another gem. I believe in using as few gems as possible, and using a gem isn't necessary here.
您不应该在资产管道之外加载您的 JS 或 CSS 文件,因为您会失去使 Rails 如此出色的重要功能。而且你不需要另一个宝石。我相信使用尽可能少的宝石,在这里不需要使用宝石。
What you want is known as "Controller Specific Javascript" ("Action Specific Javascript is included at the bottom). This allows you to load a specific JavaScript file for a specific CONTROLLER. Trying to connect your Javascript to a View is kind of... backwards and doesn't follow the MVC design pattern. You want to associate it with your Controllers or actions inside your Controllers.
您想要的是“特定于控制器的 Javascript”(“特定于操作的 Javascript 包含在底部)。这允许您为特定的控制器加载特定的 JavaScript 文件。尝试将您的 Javascript 连接到视图是一种...... . 向后并且不遵循 MVC 设计模式。您希望将其与您的控制器或控制器内的操作相关联。
Unfortunately, for whatever reason, Rails devs decided that by default, every page will load every JS file located in your assets directory. Why they decided to do this instead of enabling "Controller Specific Javascript" by default I will never know. This is done through the application.js file, which includes the following line of code by default:
不幸的是,无论出于何种原因,Rails 开发人员决定默认情况下,每个页面都将加载位于您的资产目录中的每个 JS 文件。为什么他们决定这样做而不是默认启用“控制器特定的 Javascript”,我永远不会知道。这是通过 application.js 文件完成的,该文件默认包含以下代码行:
//= require_tree .
This is known as a directive. It's what sprockets uses to load every JS file in the assets/javascripts directory. By default, sprockets automatically loads application.js and application.css, and the require_tree directive loads every JS and Coffee file in their respective directories.
这称为指令。这是 sprockets 用于加载 assets/javascripts 目录中的每个 JS 文件的内容。默认情况下,链轮会自动加载 application.js 和 application.css,而 require_tree 指令会加载各自目录中的每个 JS 和 Coffee 文件。
NOTE:When you scaffold (if you aren't scaffolding, now is a good time to start), Rails automatically generates a coffeefile for you, for that scaffold's controller. If you want it to generate a standard JSfile instead of a coffeefile, then remove the coffee gemthat is enabled by default in your Gemfile, and your scaffold will create JS files instead.
注意:当您搭建脚手架时(如果您不是搭建脚手架,现在是开始的好时机),Rails 会自动为您生成一个咖啡文件,用于该脚手架的控制器。如果你想让它生成一个标准的 JS文件而不是一个咖啡文件,那么删除你的Gemfile 中默认启用的咖啡 gem,你的脚手架将创建 JS 文件。
Ok, so the first stepto enabling "Controller Specific Javascript" is to remove the require_tree code from your application.js file, OR change it to a folder within your assets/javascripts directory if you still need global JS files. I.E.:
好的,因此启用“控制器特定 Javascript”的第一步是从 application.js 文件中删除 require_tree 代码,或者如果您仍然需要全局 JS 文件,请将其更改为 assets/javascripts 目录中的文件夹。IE:
//= require_tree ./global
Step 2:Go into your config/initializers/assets.rb file, and add the following:
第 2 步:进入您的 config/initializers/assets.rb 文件,并添加以下内容:
%w( controllerone controllertwo controllerthree ).each do |controller|
Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
end
Insert the Controller names that you want.
插入所需的控制器名称。
Step 3:Replace the javascript_include_tag in your application.html.erb file with this (note the params[:controller] part:
第 3 步:将 application.html.erb 文件中的 javascript_include_tag 替换为此(注意 params[:controller] 部分:
<%= javascript_include_tag 'application', params[:controller], 'data-turbolinks-track': 'reload' %>
Restart your server and viola! The JS file that was generated with your scaffold will now only load when that controller is called.
重新启动您的服务器和中提琴!使用脚手架生成的 JS 文件现在只会在调用该控制器时加载。
Need to load a specific JS file on a specific ACTION in your controller, I.E. /articles/new? Do this instead:
需要在控制器的特定 ACTION 上加载特定的 JS 文件,IE /articles/new?改为这样做:
application.html.erb:
application.html.erb:
<%= javascript_include_tag "#{controller_name}/#{action_name}" if AppName::Application.assets.find_asset("#{controller_name}/#{action_name}") %>
config/initializers/assets.rb:
配置/初始值设定项/assets.rb:
config.assets.precompile += %w(*/*)
Then add a new folder with the same name as you controller in your assets/javascripts folder and put your js file with the same name as your action inside. It will then load it on that specific action.
然后在 assets/javascripts 文件夹中添加一个与控制器同名的新文件夹,并将与您的操作同名的 js 文件放入其中。然后它将在该特定操作上加载它。
回答by Syed
The preferred way to add JS is in footer, so you can do this way:
添加 JS 的首选方式是在页脚中,因此您可以这样做:
show.html.erb:
show.html.erb:
<% content_for :footer_js do %>
This content will show up in the footer section
<% end %>
layouts/application.html.erb
布局/application.html.erb
<%= yield :footer_js %>
回答by Bill
Ok so maybe this is like the worst work around ever but i creat a controller method that just rendered out the .js file
好吧,也许这就像有史以来最糟糕的工作,但我创建了一个控制器方法来渲染 .js 文件
Controller
控制器
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
View
看法
%script{:src => @script, :type => "text/javascript"}
if for some reason we don't want to do this then let me know.
如果由于某种原因我们不想这样做,请告诉我。

