Rails 5 开发进阶
  • Rails 6 开发进阶
  • Active Model 功能模块
    • Model - 核心
      • Validations
      • Validator
      • Errors
      • Validations 相关的 Callbacks
      • Conversion
      • Naming & Name
      • Translation
      • Lint Tests
    • Model 的增强模块
      • Attribute Assignment
      • Attribute Methods
      • Dirty
      • Secure Password
      • Forbidden Attributes Protection
      • Serialization
      • Callbacks - 快速提供 3 个回调方法
    • 其它
  • Active Record 数据库操作:增删查改
    • Relation
      • Relation 文件下的方法
      • Query Methods
        • Preload, Eagerload, Includes 和 Joins 等
        • Query Methods 读取、设置查询方法
        • 关联表复杂查询示例
      • Spawn Methods
      • Batches 批量查询
      • Finder Methods
      • Calculations 统计计算
      • 其它
    • Collection Proxy
    • Scoping
    • Attribute Methods
      • Attribute Methods 文件下的内容
      • Read & Write
      • Before Type Cast - 类型转换
      • Query - 后缀 '?' 问询
      • Serialization
      • Primary Key
      • 其它
    • Persistence
      • 数据更新方法对比
      • 对比,然后使用合适的方法
      • 多个 save 方法
    • Counter Cache 计数器
    • Querying
    • 其它
  • Active Record 数据库关联关系
    • Associations 文件 - 4 个关联方法
    • Aggregations - composed_of 方法
    • Builder - 功能的实现
      • Association
      • Singular Association
      • Collection Association
      • Has One
      • Belongs To
      • Has Many
      • Has And Belongs To Many
    • Reflection - 实现之关联两者
      • Abstract Reflection
      • Macro Reflection
      • Association Reflection
      • Aggregate Reflection
      • Has Many Reflection
      • Has One Reflection
      • Belongs To Reflection
      • Has And Belongs To Many Reflection
      • Through Reflection
      • Polymorphic Reflection
      • Runtime Reflection
    • Association 目录 - 实现之提供方法
      • Association
      • Belongs To Association
      • Belongs To Polymorphic Association
      • Collection Association
      • Foreign Association
      • Has Many Association
      • Has Many Through Association
      • Has One Association
      • Has One Through Association
      • Singular Association
      • Through Association
    • 4 个关联方法的使用
      • belongs_to
      • has_one
      • has_many
      • has_and_belongs_to_many
      • 关联方法的可选参数汇总
    • 4 个关联方法的补充
      • 使用关联方法后,Rails 自动生成了哪些方法
      • habtm vs has_many through
    • Nested Attributes 嵌套属性
    • Inheritance 单表继承
    • 其它
      • Autosave Association
      • Alias Tracker
      • Association Scope
      • Join Dependency
      • Preloader
      • Association Relation
  • Active Record 数据库特性及功能模块
    • Callbacks 回调
      • 回调及其顺序
      • 跳过回调
      • 可选参数
      • after_create 与 after_commit on create 各自存在的坑
    • Transactions 事务
    • Locking 锁
    • Enum 枚举
    • Store
    • Validations 校验
    • Secure Token
    • Integration
    • No Touching
    • Touch Later
    • Attributes
    • Readonly Attributes
    • Serialization
    • Suppressor
  • Active Record 数据库迁移:表/字段
    • Connection Handling 连接数据库
    • Migration 文件下的内容
      • 控制台里迁移、回滚等命令
      • say_with_time
    • Connection Adapters
      • Schema Statements
        • create_table
        • change_table
      • Table Definition
      • Table
      • Database Statements
    • Model Schema
    • Schema
    • 其它
      • schema_format
      • Schema Migration
  • Active Record 数据库连接:底层适配,约定、配置
    • Naming Conventions
    • Schema Conventions
    • Timestamps
    • Core
      • 获取 record 对象
    • Sanitization
    • Migration DatabaseTasks
    • Statement Cache
    • Collection Cache Key
    • Attribute Mutation Tracker
    • Attribute Decorators
    • 其它
  • Action View 布局、渲染相关
    • Layouts
    • Base - 为渲染打基础
    • 非 Rails 是如何渲染的
    • Rails 是如何渲染的
      • Rendering
    • 渲染器介绍
      • Renderer - 渲染的入口
      • 基类 Abstract Renderer
      • 子类 Template Renderer
      • 子类 Partial Renderer & Collection Caching
      • 子类 Streaming Template Renderer
    • Template 内容
      • template 本文件下的内容
      • template 目录
    • Lookup Context
      • View Paths
      • Details Key & Details Cache
    • view_context
      • Context
      • Output Flow & Streaming Flow
    • View Paths
    • 其它
      • Output Buffer & Streaming Buffer
  • Action View 提供的 Helper 方法
    • 与表单直接相关的辅助方法
      • Form Builder
        • 扩展 Form Builder
      • Form Helper
      • Form Options Helper
      • Form Tag Helper
    • 与表单非直接相关的辅助方法
      • Tag Helper
      • Url Helper
      • Asset Tag Helper
      • Cache Helper
        • 片段缓存和 Cache Key
      • Controller Helper
      • Asset Url Helper
      • Csrf Helper
      • Capture Helper
      • Debug Helper
      • Date Helper
      • JavaScript Helper
      • Number Helper
      • Output Safety Helper
      • Rendering Helper
      • Record Tag Helper
      • Sanitize Helper
      • Translation Helper
      • Text Helper
      • Atom Feed Helper
      • Active Model Instance Tag
    • 其它
  • Action View 其它类和模块
    • Record Identifier
    • Routing Url For
    • Model Naming
    • Digestor
      • Dependency Tracker
    • 其它
  • Action Dispatch Http 作用:请求、响应
    • Request
      • Request 文件下的内容
      • URL
      • Headers
      • Mime Negotiation
      • Parameters
      • Parameter Filter & Filter Parameters
      • Cache 之 Request
      • Uploaded File
      • Utils
    • Response
      • Response 文件下的内容
      • Filter Redirect
      • Cache 之 Response
    • 其它
      • Rack Cache
      • Mime Type register
      • Session
  • Action Dispatch Middleware 中间件
    • Middleware
      • Rack - Ruby Web server 接口
      • 查看项目用了哪些 Middleware
      • 定制 Middleware
      • Middleware Stack
    • 各个 Middleware 类
      • Static
      • SSL
      • Show Exceptions
      • Exception Wrapper
      • Public Exceptions
        • 定制 Public Exceptions
      • Debug Exceptions
      • Request Id
      • Remote Ip
      • Reloader
      • Params Parser
      • Flash
      • Cookies & ChainedCookieJars
      • Session
      • Callbacks
      • Load Interlock
      • Executor
      • Debug Locks
  • Action Dispatch Routing 路由顶层(表现形式)
    • Mapper
      • Base
      • Http Helpers
      • Scoping
        • scope
        • namespace
      • Concerns
      • Resources
      • Scope、Mapping、Constraints
      • Redirection
      • match 和 scope 方法 - 重中之重
      • 路由常用方法汇总
    • 其它
      • Polymorphic Routes
      • Url For
      • Routing 概述:生成、存储、识别
      • 一步步分析从请求到响应涉及到 Rails 的哪些模块
      • endpoint 和 inspector 文件
  • Action Dispatch RouteSet 路由底层(实现方式)
    • 实例对象和各个实例方法
    • Named Route Collection
    • Dispatcher
    • Generator
    • Routes Proxy
    • Journey
  • Abstract Controller
    • Base
      • 获取所有的 Controller 和 action
    • Helpers
    • Callbacks
    • Rendering
    • render 参数汇总与详解
      • 更多关于渲染
    • Translation
    • Collector
    • 其它
      • Asset Paths
      • Routes Helpers
      • Logger
      • Url For
    • Caching
    • Caching & Caching Fragments
      • 默认片段缓存策略
  • Action Controller - Rack 增强扩展
    • Metal - 增强的 Rack, 简陋的 Controller
      • Metal 文件下的内容
      • Middleware Stack
      • Metal 使用举例
    • API - Metal 的继承者
    • Base - Metal 的继承者
    • Metal 的扩展
      • Redirecting
      • Head
      • Conditional Get - HTTP Cache
        • Conditional Get 其它
      • Etag With Template Digest
      • Http Authentication
        • Basic
        • Digest
        • Token
      • Streaming
      • Live
      • Mime Responds & Collector
      • Renderers 增删渲染器
      • Params Wrapper
      • Request Forgery Protection
      • Parameters & Strong Parameters
      • Data Streaming
      • Force SSL
      • Flash
      • Helpers
      • Cookies
      • Implicit Render
      • Instrumentation
      • Rendering
      • Rescue
      • Url For
      • 其它
    • 其它
      • Form Builder
      • Renderer
      • Basic Implicit Render
      • Railties Helpers
  • Active Support 扩展:autoload 的类和模块
    • Autoload
      • autoload & eager_autoload 补充
    • Lazy Load Hooks
    • Concern
    • File Update Checker
    • Notifications
      • Rails 默认已有的 instrumenter
    • Subscriber
    • Log Subscriber
      • Action Mailer Log Subscriber
      • Action Controller Log Subscriber
      • Action View Log Subscriber
      • Active Record Log Subscriber
    • Rescuable
    • Descendants Tracker
    • Dependencies
  • Active Support 扩展:eager_autoload 的类和模块
    • Cache 缓存的源头
    • Callback 方法解释及使用
    • Callbacks 底层简要分析
    • Configurable
    • Ordered Hash 和 Ordered Options
    • Inflector
    • Key Generator 和 Caching Key Generator
    • Message Encryptor 和 Message Verifier
    • String Inquirer - Rails.env.production?
    • Array Inquirer
    • Tagged Logging
    • Gzip 与 JSON
    • Backtrace Cleaner
    • Number Helper
    • Benchmarkable
    • Xml Mini
    • Multibyte
    • Deprecation
    • 其它
  • Active Support 核心扩展
    • Array
    • Benchmark
    • Big Decimal
    • Class
    • Date
    • Time
    • Date Time
    • Duration
    • Time With Zone
    • Time Zone
    • Enumerable
    • File
    • Hash
    • Hash With Indifferent Access
    • Integer
    • Numeric
    • Kernel
    • Object
    • Module
      • alias_method_chain
    • Marshal
    • Range
    • Regexp
    • Secure Random
    • String
    • URI
    • Load Error
    • Name Error
    • Logger
    • Logger Silence
  • Active Support 其它类和模块
    • Security Utils
  • railties 核心:初始化、组件化
    • Railtie
      • Railtie 文件下的内容
      • Initializable
      • Configuration
      • 定制自己的 Railtie
    • Railtie 补充
      • Rails 默认组件都是 Railtie
    • Engine
      • Engine 文件下的内容
      • Configuration
      • Engine full vs mountable
      • 定制自己的 Engine
      • 其它
    • Application
      • Application 文件下的内容
      • Bootstrap
      • Finisher
      • Configuration
      • Default Middleware Stack
      • Rails 应用启动过程
    • Application 补充
      • Routes Reloader
      • rake & rails 命令
      • rails console 里的小技巧
      • 路径 - Root 和 Path
      • 提示信息页面
    • 其它
      • Rails 文件下的内容
      • Configuration Middleware Stack Proxy
      • AppName, Application. Engine, Railtie
      • Backtrace Cleaner
      • Rack Logger
      • Generators
  • Rails Configuration 配置
    • 一般常用配置项
    • Action Mailer
    • Active Record
    • Action Controller
    • Action Dispatch
    • Action View
    • Active Support
    • I18n
    • Generators
    • Assets
    • Environments
    • 设置项补充
    • Middleware
  • Rails Generators 代码生成器
    • Thor
    • generators 下的目录、文件
    • Base
    • Actions
    • Named Base
    • 其它
      • App Base
      • Generators 文件下的内容
      • Migration
      • Active Model
      • Resource Helpers
      • Model Helpers
      • Generated Attribute
  • Action Mailer 发邮件
    • Base
      • 拦截器 register_interceptor
      • 订阅者 register_observer
    • Mail Helper
    • Message Delivery
    • 其它
      • Delivery Methods
      • Previews & Preview
      • DeliveryJob
      • Collector
  • Active Job 异步任务
    • Active Job 使用
    • Active Job 补充
  • Action Cable 封装的 WebSockets
    • 服务端 - Ruby 代码
      • Channel
      • Channel 补充
      • Connection
      • Connection 补充
      • Server
      • Server 补充
      • Remote Connections
      • Action Cable Helper
      • Subscription Adapter
      • Subscription Adapter 补充
    • 客户端 - Coffee 脚本
      • Action Cable 文件下的内容
      • Consumer
      • Subscription
      • Connection
      • Subscriptions
      • Connection Monitor
    • 一些重要的东西
    • 其它
  • Active Storage 存储功能最小实现
  • 前端 Turbolinks
  • 前端 Webpacker
  • 测试 Testing
    • Active Support
    • Active Job
    • Action Mailer
    • Action Controller
    • Action Dispatch
    • Action View
    • Generators
    • rails-dom-testing
  • 测试 MiniTest
    • Spec DSL
    • Assertions
    • Mock
    • Unit
      • TestCase
      • Lifecycle Hooks
      • Guard
    • Expectations
    • 其它
  • 测试 Factory Girl
  • rails-guides 指南
  • 其它
    • 继承心得
    • Rails 源代码里一些常用方法
    • Rails assets precompile
    • Turbolinks 产生的原因
    • Turbolinks 3
    • Turbolinks 补充
    • Turbolinks 5
  • 后记
由 GitBook 提供支持
在本页
  • Ruby 部分
  • JS 部分
  • 一些特性
  • 坑及策略
  • JS 要如何更改使用?
  • 其它类和对象

这有帮助吗?

  1. 其它

Turbolinks 补充

简单理解概念:把原来所有 GET 请求(包括链接、重定向、浏览器的后退)都通过 AJAX 来实现,并且 url 是变化的。

使用 turblinks 的话,注意:一,尽量从 AJAX 的角度出发写监听事件;二,尽量使用 turblinks 提供的监听事件。

Ruby 部分

重写了 ActionController::Base 里的 redirect_to 和 render 方法

ActionController::Base.ancestors.select{|a| a.to_s =~ /^Turbolinks/}
 => [Turbolinks::XHRHeaders, Turbolinks::Cookies,
     Turbolinks::XDomainBlocker, Turbolinks::Redirection]

render 使用的是 Turbolinks.replace redirect_to 使用的是 Turbolinks.visit

处理 :back 这种情况,使用 X-XHR-Referer 标识

更改了 url_for 方法(会影响到 link_to 等调用到它的方法)

当 url_for 使用到 :back 参数时有用,它会把原来 header 里的 HTTP_REFERER 改为 HTTP_X_XHR_REFERER

原因:Turbolinks 获取内容的时候使用 XMLHttpRequest 发起请求(简称 XHR)

带来的问题:XHR 请求的 HTTP 头 Referer 并不正确

解决办法:添加了 X-XHR-Referer 头,后端程序获取 Referer 的时候,需要先取 X-XHR-Referer。

module XHRUrlFor
  def self.included(base)
    base.alias_method_chain :url_for, :xhr_referer
  end

  def url_for_with_xhr_referer(options = {})
    options = (controller.request.headers["X-XHR-Referer"] || options) if options == :back
    url_for_without_xhr_referer options
  end
end

# 辅助方法
def referer
  self.headers['X-XHR-Referer'] || super # super 就是 self.headers['Referer']
end
alias referrer referer

覆盖了 Redirect 的 call 方法,修复 redirect_to 里的 bug

def call_with_turbolinks(env)
  status, headers, body = call_without_turbolinks(env)

  if env['rack.session'] && env['HTTP_X_XHR_REFERER']
    env['rack.session'][:_turbolinks_redirect_to] = headers['Location']
  end

  [status, headers, body]
end
alias_method_chain :call, :turbolinks

注意:上面设置了头 X-XHR-Redirected-To

其它几点

一,3 个钩子

before_action :set_xhr_redirected_to, :set_request_method_cookie
after_action :abort_xdomain_redirect

1) 因为 trublinks 改变了原来 redirect_to 的行为,带来了新的问题,然后它又提供了解决办法:

  def set_xhr_redirected_to
    if session && session[:_turbolinks_redirect_to]
      response.headers['X-XHR-Redirected-To'] = session.delete :_turbolinks_redirect_to
    end
  end

对应 redirect_to :back 这种情况,使用 X-XHR-Referer 标识;用 X-XHR-Redirected-To 记录重定向的目标地址。

2) 它怎么记录是非 GET 请求的呢?用 cookies 记录。

  def set_request_method_cookie
    if request.get?
      cookies.delete(:request_method)
    else
      cookies[:request_method] = request.request_method
    end
  end

对于非 GET 请求,turblinks 是不起作用的。

3) 跨域重定向:

  def abort_xdomain_redirect
    to_uri = response.headers['Location']
    current = request.headers['X-XHR-Referer']
    unless to_uri.blank? || current.blank? || same_origin?(current, to_uri)
      self.status = 403
    end
  rescue URI::InvalidURIError
  end

某种情况下,禁止访问。

JS 部分

所有对外 API

Public API
   Turbolinks.visit(url)
   Turbolinks.pagesCached()
   Turbolinks.pagesCached(20)
   Turbolinks.cacheCurrentPage()
   Turbolinks.enableTransitionCache()
   Turbolinks.disableRequestCaching()
   Turbolinks.ProgressBar.enable()
   Turbolinks.ProgressBar.disable()
   Turbolinks.ProgressBar.start()
   Turbolinks.ProgressBar.advanceTo(80)
   Turbolinks.ProgressBar.done()
   Turbolinks.allowLinkExtensions('md')
   Turbolinks.supported
   Turbolinks.EVENTS

# 去除重复的有:
  visit,
  replace,
  pagesCached,
  cacheCurrentPage,
  enableTransitionCache,
  disableRequestCaching,
  ProgressBar: ProgressBarAPI (包括:enable, disable, start, addvanceTo, done),
  allowLinkExtensions: Link.allowExtensions,
  supported: browserSupportsTurbolinks,
  EVENTS: clone(EVENTS)

配置项:

cacheSize 默认缓存 10 个页面

transitionCacheEnabled 事务缓存?默认为 false

requestCachingEnabled 请求缓存?默认为 true

progressBar 进度条

currentState 当前状态 loadedAssets 加载资源

referer 后退链接

xhr 异步请求

所有事件:

EVENTS =
  BEFORE_CHANGE:  'page:before-change'
  FETCH:          'page:fetch'
  RECEIVE:        'page:receive'
  CHANGE:         'page:change'
  UPDATE:         'page:update'
  LOAD:           'page:load'
  RESTORE:        'page:restore'
  BEFORE_UNLOAD:  'page:before-unload'
  EXPIRE:         'page:expire'

具体做了什么事,如何实现,可以查看对应源代码,在此不做讨论。

一些特性

Transition Cache

前面不是说过 turblinks 默认可以缓存 10 个页面吗? 现在问题来了:如果我要访问一个已经存在缓存里的页面,它是"直接从缓存里取",还是"改为了 AJAX 实现重新从服务端取"呢?

默认还是从"改为了 AJAX 实现重新从服务端取"。不过,你可以通过以下配置,让它"直接从缓存里取":

Turbolinks.enableTransitionCache();

Partial replacements

你可以使用

Turbolinks.visit(path, options)

或

Turbolinks.replace(html, options)

实现局部替换 HTML 文档内容。

坑及策略

事件的改变

1) 点击链接:

page:before-change # 链接刚刚被点击,turblinks 刚准备起作用的状态
page:fetch         # 从服务端获取内容
page:receive       # 已经收到服务器返回内容,但还没处理(去掉 header 等)的状态
page:before-unload # 已经处理完成,但还没替换的状态
page:change        # 已切换到新页面的状态
page:load          # 整个点击彻底的完成

2) 而使用浏览器历史返回上一页:

page:before-unload # 页面已经从缓存里取出,准备切换
page:change        # 已切换到新页面的状态
page:restore       # 整个回退彻底的完成

3) 其它:

# 到目前为止,我们就有两类 AJAX 请求了。
# 一是 turblink 转换过来的 AJAX,二是我们编写的、真正的 AJAX.
# 使用下面这个状态,可以同时监听上述两种 AJAX 引起的页面变化。
page:update

# 手动缓存当前页面
Turbolinks.cacheCurrentPage();

# 页面缓存数量达到上限时,触发它:
page:expire

# 效果和 fetch 一样,只不过多了个判断。
# 如果浏览器支持 turblinks 那么使用 turblinks 的 fetch.
# 如果浏览器不支持 turblinks 那么使用普通的访问
Turbolinks.visit

# 局部替换 HTML 文档内容
Turbolinks.replace

JS 要如何更改使用?

jquery.turbolinks 实践,请按照 AJAX 的方式写 JS 代码。

/* 不要这么写 */
$(function() {
  $(document).on('click', 'button', function() { ... })
});

/* 而是这么写 */
$(document).on('click', 'button', function() { ... })

和

// 不要这么写
$(document).on('ready', function () { /* ... */ });

// 而是这么写
$(document).ready(function () { /* ... */ });
$(function () { /* ... */ });

怎样防止浏览器缓存 Turbolinks 请求:

# 全局
Turbolinks.disableRequestCaching()

# 每个请求
Turbolinks.visit url, cacheRequest: false

像 jQuery.ajax(url, cache: false), 会被追加 "_#{timestamp}" 到 GET 请求参数里。

如何移除

# Gemfile

# 注释这一行:
gem 'turbolinks'
# app/assets/javascripts/application.js

# 移除这一行:
//= require turbolinks

如果有 js 逻辑绑定了DOMContentLoaded 事件,就需要为 Turbolinks 做兼容

语法或历史遗留问题,可以使用以下方法:

# Gemfile:
gem 'jquery-turbolinks'
# Add it to your JavaScript manifest file, in this order:
//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//
// ... your other scripts here ...
//
//= require turbolinks

几个 data-* 属性

data-no-transition-cache

data-turbolinks-permanent

data-no-turbolink

data-method, data-remote, or data-confirm

data-turbolinks-track

data-turbolinks-eval

data-turbolinks-temporary

原来的 DOM 操作怎么办?并且它们是非幂等的

DOM 操作最好是幂等。如果不是幂等的,你可以使用使用 page:load 而不是 page:change

// using jQuery for simplicity

$(document).on("ready page:load", nonIdempotentFunction);

其它类和对象

Click 管理着链接和点击事件,触发时会进行检查。如果符合 trublinks 则用 AJAX 执行请求,否则改用普通的请求。

ProgressBar 进度条。对应 class name 为 turbolinks-progress-bar

ProgressBarAPI 管理进度条可用的接口。有:

enable
disable

start
done

advanceTo

CSRFToken 管理 csrf token,提供接口:

get
update

Link 对于已经存在的链接,进行一些特殊处理。 比如,前面提到过的,有的链接不能使用 turblinks

各种浏览器不同引起的问题

如何替换链接?

由 JS 实现。

如何防止丢失 Referer ?

压根就没有丢失,只是原来的不能用,用新的 X-XHR-Referer

参考:

上一页Turbolinks 3下一页Turbolinks 5

最后更新于5年前

这有帮助吗?

Turbolinks
jquery.turbolinks