Turbolinks和Controller特定的资产

时间:2014-07-12 06:24:28

标签: ruby-on-rails asset-pipeline turbolinks

我已修改application.html.erb以使用控制器特定资产:

application.html.erb

<!DOCTYPE html>
<html>
<head>
  <title>My Application</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= stylesheet_link_tag params[:controller], 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag params[:controller], 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>
... other html template ...

问题在于,我安装了turbolinks。当我在同一个控制器中导航时,turbolinks可以工作。但当我切换到另一个控制器时,turbolinks将执行完全重新加载。有什么方法可以解决这个问题吗?

2 个答案:

答案 0 :(得分:12)

<强> Turbolinks

Turbolinks获取HTML页面的<body>,并使用Ajax对其进行更改,使<head>区域保持不变。

如果您的<head>保持不变,则此有效 - 否则如何保持不变?因此,在更改控制器页面/资产的意义上,您将拥有来完成整页更新而不使用Turbolinks(至少如果您使用Turbolinks而不进行黑客攻击)

我建议修复此问题的方法是更改​​特定于控制器的资产结构,特别是尽可能少地对<head>区域进行更改。

-

Turbolinks Tracking

阅读Turbolinks documentation后,您可以从控制器特定资产中删除turbolinks-data-track选项中受益:

<%= javascript_include_tag controller_name, 'data-turbolinks-track' => false %>
  

您可以跟踪某些资产,例如application.js和application.css,   您要确保的内容始终是最新版本   Turbolinks会议。这是通过标记这些资产链接来完成的   data-turbolinks-track,如下:

     

<link href="/assets/application-9bd64a86adb3cd9ab3b16e9dca67a33a.css" rel="stylesheet" type="text/css" data-turbolinks-track>

     

如果这些资产更改了网址(嵌入了md5标记以确保这一点),则该网页将完整填写   重装而不是通过Turbolinks。这确保了所有   Turbolinks会话将始终使用您最新的JavaScript   和CSS。

-

controller_name

您将从中受益的是使用controller_name帮助程序(代替params[:controller]):

<%= javascript_include_tag 'application', controller_name, 'data-turbolinks-track' => true %>

答案 1 :(得分:4)

将控制器特定的j放在body标签中。由于turbolinks不会触及html主体,因此每次访问页面时都会重新加载那段js代码。

在你的情况下

<body>
  <%= javascript_include_tag params[:controller] %>
  ...
</body>

但是如果您的控制器js中有很多代码,您可能会注意到上面的解决方案非常耗时。因为当您访问该页面时,将重新加载该大块代码。那怎么处理呢?


■以下方法可能会导致某些jquery事件多次绑定。这是turbolinks的问题。阅读这篇文章http://staal.io/blog/2013/01/18/dangers-of-turbolinks/

更有效的解决方案

基本上,当用户第一次访问您的站点时,您加载所有js代码,确保控制器特定的代码不会运行(分别将它们包装在函数中)并将它们保存在全局变量中,例如{{1} }。然后通过编写类似

的内容来触发特定于控制器的js
Site
身体标签中的

这样,实际的控制器特定的js代码只加载一次并在需要时被触发。

实施

<script> $(document).on("ready page:load", function () { Site.load('<%= controller_name %>'); } </script>

app/assets/javascripts/site.js

将控制器js包装在函数中并将它们保存到var site; if(!window.Site) { site = window.Site = {}; site.controllers = {} site.load = function (controller) { if (this.controllers.hasOwnProperty(controller)) { this.controllers[controller].call(); } }; site.add = function (controller, fn) { this.controllers[controller] = fn; } } 。例如,Site

users.js

app/assets/javascripts/site.js
你的application.js中的

加载它们。

Site.add("users", function () { // UserController related js code }

app/assets/javascripts/site.js

然后在布局中触发控制器特定的js。

//= require jquery //= require jquery_ujs //= require turbolinks //= require site //= require_tree .

app/views/layouts/application.html.erb

特定于动作的js代码怎么样?

只需修改<body> <script> $(document).on("page:load", function () { Site.load('<%= controller_name %>'); } </script> <%= yield %> </body> 和布局即可。我最后用以下片段结束了。

site.js

(function (global) { var site; if(global.Site) { return; } site = global.Site = {}; site.controllers = {}; site.actions = {}; site.load = function (name) { var keys = name.split("."); var c = keys[0]; var cs = this.controllers; var as = this.actions; var i; if (cs.hasOwnProperty(c)) { for (i =0 ; i < cs[c].length; i++) { cs[c][i].call(); } } if (keys.length > 1 && as.hasOwnProperty(name)) { for (i =0 ; i < as[name].length; i++) { as[name][i].call(); } } }; site.add = function (name, fn) { var keys = name.split("."); var lv = keys.length > 1 ? this.actions : this.controllers; if (!lv.hasOwnProperty(name)) { lv[name] = [fn]; } else { lv[name].push(fn); } }; })(window);

app/views/layouts/application.html.erb

相关

这是一个有趣的视频,关于为您可能想要观看的单页应用加载javascript,css和其他资源。

OSCON 2014:Instagram.com如何运作;皮特亨特

https://www.youtube.com/watch?v=VkTCL6Nqm6Y