<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>gerry (gerry)</title>
    <link>https://ruby-china.org/gerry</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>Rails 路由系统源码探索</title>
      <description>&lt;p&gt;&lt;strong&gt;注：本帖不是使用手册，仅仅分享自己探索源码的一些理解，以便有共同爱好的朋友一起共勉，本人水平有限，也是初次发帖，恳请大家拍砖轻点&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;源码版本：4.2.0.beta&lt;/p&gt;
&lt;h2 id="Route概述"&gt;Route 概述&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Action Pack 是 Rails 的核心框架之一，负责从 Request 到 Response 的整个处理过程，Action Pack 提供了 Request、Routing、Controller、Action、Views、Response 的完整实现，在 MVC 模型中，Action Pack 实现了 Controller 和 View（注：View 的具体实现由 Action View 模块，但 Action Pack 负责 View 的逻辑调用关系）两部分，Action Pack 有两大核心模块：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Action Dispatch：主要负责分析 Web Request 的信息参数，查找用户自定义的路由信息，分发到目标处理程序，一个 Controller’s Action 或者一个 Rack Base  Application，又或者一个 Rails Engine，又或者另外一个路由器。目标处理程序处理完成后，返回 Rack Base 的 Response [ status, headers, [body] ]，最终返回给应用服务器，通过应用服务器返回客户浏览器。   &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Action Controller：提供了一个 Base Controller 的实现，Base Controller 提供了 Filters 和 Actions，隐藏了 Controller 与 View、Template 之间的数据传递、调用关系及多种 Helper 模块的自动 Mixin，以便开发者集中精力开发本身的业务逻辑。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rails 路由是 Action Pack 的核心子系统，属于 Action Dispatch 模块，系统框架图：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/13785a3d602f8a7b156eec010eef2513.png" title="" alt="System Diagram"&gt;&lt;/p&gt;

&lt;p&gt;类图：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/79ed99604da7abe7f22265b990c3aaec.jpg" title="" alt="ClassDiagram"&gt;&lt;/p&gt;

&lt;p&gt;路由的实质是什么，路由就是一种简单的映射关系，路径 Path 到目标 App 的映射，非常简单，无需过多解释，但现实世界往往一句简单的描述，演变成一个复杂的过程和系统，因为在一句简单的描述前面和后面都会加上非常多的限定词，也就是人们的需求往往远大于简单的描述，如 Rails 的 Routing 会加上简单、智能、快速，以及 Rails 的核心价值观“约定优于配置”，这些限定词就让 Rails 的路由系统不那么简单。Rails 路由系统分为三个部分：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;路由映射；&lt;/li&gt;
&lt;li&gt;URL 自动生成 &lt;code&gt;Generator&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;路由识别与分发&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;注：以下所有未注明 module 的类和模块，都默认是 &lt;code&gt;ActionDispatch::Routing&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="路由映射"&gt;路由映射&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;路由映射涉及到的类和模块：&lt;code&gt;Mapper、Mapping、Scope、Resource、SingletonResource&lt;/code&gt;，模块：&lt;code&gt;Base、HttpHelpers、Scoping、Resources、Concerns&lt;/code&gt;，类关系图如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/b1a0e8c53d311d2956087c79ece9655b.jpg" title="" alt="Route Class Diagram"&gt;&lt;/p&gt;

&lt;p&gt;Mapper 是路由映射器，所有路由映射都是通过 Mapper 对象来映射，但其核心功能都是通过 include 其他模块来实现，按如下顺序 include 到 Mapper 类中：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Base&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;HttpHelpers&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Redirection&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Scoping&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Concerns&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Resources&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注：因为所有 module 都会 include 到 Mapper 类，未注明 module 的方法，都默认是 Mapper 对象的实例方法&lt;/p&gt;

&lt;p&gt;其中需要注意的是 Base 模块必须在最前面，因为 Base 模块定义了 root、match、mount 三个模块实例方法，其中 root、match 都会被其 Resources 模块重载。&lt;/p&gt;

&lt;p&gt;Rails 中的路由配置通常都是&lt;code&gt;Rails.application.routes.draw do … end&lt;/code&gt;，与其他非 Ruby 框架不一样，其他框架大都是通过配置文件（通常都是 XML 文件）来配置路由，一般配置文件如 XML 文件都是要先加载配置文件，然后通过 XmlParser 分析配置文件，最后通过分析结果进行处理相应的配置。Rails 的路由文件 routes.rb 并不是传统意义上的配置文件，其本身就是一段可以执行的脚本文件，他与其他 Ruby 源文件没有任何区别，这也是 Ruby 语言的强大之处，非常适合开发领域语言 DSL，而 Rails 路由映射的实质就是某种强大的 DSL。Rails 的路由映射具有简单、灵活、强大、智能等特点，对于 Rails 的新手来说，在配置路由时即兴奋又忐忑，简单一条配置语句，如：resources users，就会发生一系列化学变化，产生一系列你需要的结果，八条路由映射，四个路由 helper，可以说是全智能化完成配置和产生 helper 方法，为什么忐忑呢，因为太不可思议了，作为软件开发人员来说，没有做任何代码编写和配置就得到自己需要的结果，内心是有一种逆反的声音，那需要我做啥，我如果在添加一些选项又会产生什么变化呢。软件开发人员本身就喜欢掌控一切，随心所欲的修改和升级，突然觉得自己失去了掌控，无所适从，需要了解真相。&lt;/p&gt;

&lt;p&gt;Ruby 编写 DSL 语言非常方便和强大，首先不需要你额外去解析某种文件和特殊语法规则，一切尽在 Ruby 语言中，也就是说 DSL 语言本身也是某种 Ruby 代码，你所看到的不过是某个类或对象的方法而已，我个人的理解就是具有某种参数规则的一系列方法的集合，就是一种 DSL。回到 Rails 的路由映射，其实就是由 root、mount、match、scope、namespace、resource、resources、controller、constraints、defaults、concern、concerns 以及 http 方法如：GET、POST 等一系列配置方法的集合，当然还远不止这些，还有一些 resources 下的二级配置方法如：new、member、collection、nested、shallow、namespace 等。除了 resources 下的二级方法必须在 resources 作用域下，还有就是 concern 及 concerns 有限制外，几乎所有的配置都可以出现在任何地方，甚至哪些带有 block 的方法只要你愿意可以一直嵌套下去。感谢 Ruby 语言的 block，是他使 Ruby 灵活而强大。&lt;/p&gt;

&lt;p&gt;在分析之前我们来看看有哪些标准选项：&lt;/p&gt;

&lt;p&gt;:path, :as, :to, :on, :via, :shallow_path, :shallow_prefix, :module, :controller, :action, :path_names, :constraints, :shallow, :blocks, :defaults, :options, :only, :except, :param, :anchor, :format,  :concerns.&lt;/p&gt;
&lt;h3 id="路由映射上下文"&gt;路由映射上下文&lt;/h3&gt;
&lt;p&gt;这么多的方法，这么多的选项，要管理好真不是一间容易的事，如果每个方法都是独立的，那么很简单每个方法独立实现就可以，但是 Rails 的路由映射允许有多层嵌套，有上下文关系，同一个方法放在不同的上下文，最终结果都不一样的。所以要理解路由映射，就必须理解上下文（scope 虽然是范围的意思，开始我认为是作用域，但其实质与作用域相去甚远，所以最终用上下文来定义）， &lt;strong&gt;上下文是什么，可以把它理解成一个环境对象，具有非常多的属性和方法，属性就是前文列出的标准选项，每一个不同的上下文就是具有不同属性的环境对象&lt;/strong&gt;。Rails 路由映射上下文的核心就是类 Scope 和 scope 方法，scope 方法可以建立一个新的上下文，每个上下文都是一个 Scope 对象。&lt;/p&gt;
&lt;h2 id="Scope类："&gt;Scope 类：&lt;/h2&gt;
&lt;p&gt;研究一个类首先要研究其构造函数和初始化函数，因为这两个函数往往能够看到类最为核心的属性，也就能够大致理解类的实现方式以及与他关系最紧密的类。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;scope_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hash&lt;/span&gt;
  &lt;span class="vi"&gt;@parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;
  &lt;span class="vi"&gt;@scope_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope_level&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;很简单三个参数，简单三行语句，&lt;code&gt;@hash&lt;/code&gt;存放 Scope 对象的 options 的哈希表，&lt;code&gt;@parent&lt;/code&gt;表明 Scope 上下文实际上是一个链表，就是在路由映射中有非常多的 Scope 对象，通过一个链表连接在一起，同时又具有堆栈的特性，就是当前上下文永远指向最顶端的 Scope 对象，要返回到父级上下文，必须弹出自己，但是请记住在 &lt;strong&gt;当前上下文中没有某个 key 值时，当前上下文可以逐级访问父级上下文对应的 key 值，所以我把它当作链表和堆栈的结合体&lt;/strong&gt;。scope_level 其实很难理解，它与前面堆栈没有任何关系，并不代表这个堆栈的层级，而是表示当前上下文的特性，某种程度上代表是属于什么样的上下文，其取值范围：resource, resources, nested, collection, member, root, new, shallow 等。&lt;/p&gt;
&lt;h3 id="options的定义："&gt;options 的定义：&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;OPTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:shallow_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:shallow_prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:path_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:constraints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:shallow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:defaults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:options&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上就是 Scope 类定义的标准 options，也就是 Scope 只会处理已定义的选项，其他会自动忽略，你也可以把他不支持的选项全部放在:options 键值对中，他仅仅在 Mapping.build 函数中合并选项，&lt;code&gt;options = scope[:options].merge(options) if scope[:options]&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@hash.fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vi"&gt;@parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该函数实现取当前上下文中的某个选项值，但一定要记住，如果当前上下文为空，逐级取父级上下文的相应 key 的选项值，直到取到为止，这一点非常重要，否则后面非常难以理解上下文嵌套的关系。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scope_level&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;顾名思义，新创建一个上下文，把当前上下文作为 parent，以新的选项哈希表覆盖父级上下文选项表，也就是继承与覆盖了当前上下文，继承了当前上下文的选项及 scople_level，但同时用新的 hash 覆盖部分父级上下文选项表，这就是通过函数&lt;code&gt;[](key)&lt;/code&gt;实现的。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;顾名思义，新创建一个上下文，把当前上下文作为 parent，完全继承当前上下文的所有选项，仅仅是改变了 scope_level，换言之就是更改为某种特殊的上下文。&lt;/p&gt;
&lt;h3 id="scope方法:"&gt;scope 方法：&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_options!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dup&lt;/span&gt;
  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;  
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:constraints&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;nested_scope?&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow_path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow_prefix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:constraints&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;defaults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:constraints&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;URL_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Fixnum&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:defaults&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;reverse_merge!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:constraints&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:constraints&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="vi"&gt;@scope.options.each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:blocks&lt;/span&gt;
      &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:options&lt;/span&gt;
      &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
      &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"merge_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_scope"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope.new&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;
      &lt;span class="k"&gt;yield&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;
 &lt;span class="k"&gt;ensure&lt;/span&gt;
   &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope.parent&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;*args 万能参数，它可以传任意个参数，他把任一个参数转换成数组，其中 block 是自动传入，数组中最后一个参数是一个哈希表，如果有哈希表的话，首先分离万能参数的哈希表为 options。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;scope  ‘admin/’, ‘posts’, path: ‘users’ do … end&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;options[path] 是多少，是 admin/还是 posts 还是 users，以上都不是，options[path] 为 admin/posts，到处都是陷阱，也就是说传入的路径优于 path:设置的路径。
最为关键的部分是&lt;code&gt;@scope.options.each do …end&lt;/code&gt;，这部分处理通过 scope 方法创建上下文时选项继承方式，既不是简单继承也不是简单覆盖，而是根据传进来不同的选项 key，采取不同的方式，一定要记住显式传进来的选项会根据不同的 key 做不同的拼接处理，通过
&lt;code&gt;scope[option] = send("merge_#{option}_scope", @scope[option], value)&lt;/code&gt;实现，隐式的参数通过 Scope 类的&lt;code&gt;[](key)&lt;/code&gt;方法以 lazy 的方式继承父级上下问的选项参数，就是后面有显式用到的地方才会继承父级上下文。&lt;/p&gt;

&lt;p&gt;显式参数的处理 (注以下都忽略 parent 的逻辑判断，具体参照不同的函数实现)：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="ss"&gt;as:     &lt;/span&gt;&lt;span class="c1"&gt;#{parent}_#{child}        shallow_path:  #{parent}/#{child}&lt;/span&gt;
&lt;span class="ss"&gt;path:   &lt;/span&gt;&lt;span class="c1"&gt;#{parent}/#{child}        shallow_prefix： #{parent}/#{child}&lt;/span&gt;
&lt;span class="ss"&gt;module: &lt;/span&gt;&lt;span class="c1"&gt;#{parent}/#{child}        controller: child&lt;/span&gt;
&lt;span class="ss"&gt;action: &lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;                     &lt;span class="ss"&gt;shallow:  &lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="ss"&gt;path_names:  &lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;  &lt;span class="n"&gt;相同的话&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;覆盖&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;不做拼接处理&lt;/span&gt;
&lt;span class="ss"&gt;defaults:    &lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;  &lt;span class="n"&gt;相同的话&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;覆盖&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;不做拼接处理&lt;/span&gt;
&lt;span class="ss"&gt;options:     &lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;  &lt;span class="n"&gt;相同的话&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;覆盖&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;不做拼接处理&lt;/span&gt;
&lt;span class="ss"&gt;blocks:      &lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;  &lt;span class="n"&gt;相同的话&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;覆盖&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;不做拼接处理&lt;/span&gt;
&lt;span class="ss"&gt;constraints: &lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;  &lt;span class="n"&gt;相同的话&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;覆盖&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;不做拼接处理&lt;/span&gt;
&lt;span class="ss"&gt;only:    &lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;  &lt;span class="n"&gt;覆盖&lt;/span&gt;  &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;不做拼接处理&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;未设置&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;保留&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;
&lt;span class="ss"&gt;except:  &lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;  &lt;span class="n"&gt;覆盖&lt;/span&gt;  &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;不做拼接处理&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;未设置&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;保留&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后一段代码就是上下文堆栈的实现，配合 block，实现上下文的嵌套调用。&lt;/p&gt;
&lt;h3 id="root 上下文："&gt;root 上下文：&lt;/h3&gt;
&lt;p&gt;root 上下文在 Mapper 的初始化函数中创建：
&lt;code&gt;@scope = Scope.new({ :path_names =&amp;gt; @set.resources_path_names })&lt;/code&gt;，&lt;a href="/set" class="user-mention" title="@set"&gt;&lt;i&gt;@&lt;/i&gt;set&lt;/a&gt; 为 RouteSet 对象，&lt;code&gt;@set.resources_path_names&lt;/code&gt; 为 &lt;code&gt;RouteSet.default_resources_path_names&lt;/code&gt;，其值为： &lt;code&gt;｛new: 'new', edit: 'edit' ｝&lt;/code&gt;，也就是说 root 上下文，是一个非常干净的上下文，仅有 path_names 选项参数。path_names 只有在 resource 和 resources 上下文中才会有作用，而在这两个环境上下文中通过 default_actions 进一步扩展为&lt;code&gt;[:index, :create, :new, :show, :update, :destroy, :edit]&lt;/code&gt;默认设置，所以 root 上下文是一个非常干净的上下文环境。&lt;/p&gt;

&lt;p&gt;范例：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;match '/posts' =&amp;gt; 'posts#index'&lt;/code&gt;其结果为&lt;code&gt;path: /posts&lt;/code&gt;, 目标&lt;code&gt;to: PostsController#index&lt;/code&gt;。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="s1"&gt;'/admin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as: &lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;    &lt;span class="c1"&gt;#新建上下文，path:/admin, as: admin&lt;/span&gt;
  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="s1"&gt;'/user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as: &lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;    &lt;span class="c1"&gt;#新建上下文， path:/admin/user, as: admin_user&lt;/span&gt;
    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s1"&gt;'/posts'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'posts#index'&lt;/span&gt;     &lt;span class="c1"&gt;#在当前上下文环境中执行。&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;path: /admin/user/posts, to: PostsController#index, name: admin_user_posts&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="namespace 与 scope的区别："&gt;namespace 与 scope 的区别：&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;

  &lt;span class="n"&gt;defaults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;module:         &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;path:           &lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="ss"&gt;as:             &lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="ss"&gt;shallow_path:   &lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="ss"&gt;shallow_prefix: &lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;namespace 就是指定一系列默认值为 path 的 scope 实现，同时支持显式指定选项参数，显式指定参数优先于默认值。
范例：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:admin&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;产生八条路由，路径前缀为&lt;code&gt;/admin&lt;/code&gt;, 名字前缀为&lt;code&gt;admin_&lt;/code&gt;, 目标为&lt;code&gt;Admin：：PostsController&lt;/code&gt;控制器。&lt;/p&gt;
&lt;h3 id="Resources:"&gt;Resources:&lt;/h3&gt;
&lt;p&gt;资源是一种抽象定义，在 RESTful 中定义资源为任何网络实体，每一个资源都有唯一的 URI，在 Rails 中通常对应一种数据模型，Resources 正是 RESTful 的 Rails 实现。核心包括类 Resource，SingletonResource 和模块 Resources。Resources 实现了 &lt;code&gt;resource, resources, member, collection, nested, new&lt;/code&gt;等一系列方法。&lt;/p&gt;
&lt;h4 id="Resource类："&gt;Resource 类：&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;VALID_ON_OPTIONS&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:member&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;RESOURCE_OPTIONS&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:only&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:except&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:concerns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;CANONICAL_ACTIONS&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="sx"&gt;%w(index create new show update destroy)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三个常量定义，具体意义后续说明，按常规先看初始化函数：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="vi"&gt;@name&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;
  &lt;span class="vi"&gt;@path&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="vi"&gt;@name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;
  &lt;span class="vi"&gt;@controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="vi"&gt;@name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;
  &lt;span class="vi"&gt;@as&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="vi"&gt;@param&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:param&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt;
  &lt;span class="vi"&gt;@options&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;
  &lt;span class="vi"&gt;@shallow&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;太多有用信息了，一系列默认值设置，这也是约定优于配置的具体表现，如果不显式设置选项参数，那么所有的都是实体的名称，除了 param:参数设为:id 之外。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plural&lt;/span&gt;
  &lt;span class="vi"&gt;@plural&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;singular&lt;/span&gt;
  &lt;span class="vi"&gt;@singular&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singularize&lt;/span&gt;
&lt;span class="no"&gt;End&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resource_scope&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:controller&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="ss"&gt;:member_name&lt;/span&gt; &lt;span class="ss"&gt;:singular&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;collection_name&lt;/span&gt;
  &lt;span class="n"&gt;singular&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;plural&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;plural&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_index"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;plural&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;member_scope&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="ss"&gt;:shallow_scope&lt;/span&gt; &lt;span class="ss"&gt;:member_scope&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;new_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nested_param&lt;/span&gt;
  &lt;span class="ss"&gt;:"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;singular&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="ss"&gt;_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="ss"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nested_scope&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;nested_param&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="no"&gt;End&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上一系列方法，主要分为两类，&lt;code&gt;xxx_scope，xxx_name&lt;/code&gt;，&lt;code&gt;xxx_scope&lt;/code&gt;主要是用于 resource 上下文的二级方法，或者说某种特定上下文环境如 collection, member 等:path 一部分或全部，&lt;code&gt;xxx_name&lt;/code&gt;则是:as 的一部分或全部，请记住与 scope 一样，单个来看 Resource 是没什么意义的，一定要在上下文堆栈中才能得到最终结果。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SingletonResource&lt;/code&gt; 是 &lt;code&gt;Resource&lt;/code&gt; 的子类，不是一个单例类，而是一个单利资源，就是该资源只有单数形式访问和存在，最典型的例子就是 &lt;code&gt;Profile&lt;/code&gt;，不同之处：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="ss"&gt;:member_name&lt;/span&gt; &lt;span class="ss"&gt;:singular&lt;/span&gt;
&lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="ss"&gt;:collection_name&lt;/span&gt; &lt;span class="ss"&gt;:singular&lt;/span&gt;
&lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="ss"&gt;:member_scope&lt;/span&gt; &lt;span class="ss"&gt;:path&lt;/span&gt;
&lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="ss"&gt;:nested_scope&lt;/span&gt; &lt;span class="ss"&gt;:path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;无论是 member 上下文还是 collection 上下文，name 都是单数形式，path 都是指向 options[:as] 或者实体名称，不会做拼接处理，从某种意义上讲都是单数形式，没有复数形式。&lt;/p&gt;
&lt;h4 id="RESOURCE_OPTIONS："&gt;RESOURCE_OPTIONS：&lt;/h4&gt;
&lt;p&gt;如前文定义，为什么 Resource 会单独定义 options 呢，前面讲过 Scope 也定义过一系列标准选项，为什么要重复定义呢，我们先来看一段代码，当我们配置 resources xxx 时，首先会执行 resources 方法，再调用函数 &lt;code&gt;apply_common_behavior_for&lt;/code&gt;，该函数有一段代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;scope_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;RESOURCE_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;scope_options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope_options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现其中秘密没，先挑选出不在 RESOURCE_OPTIONS 之中的选项参数，调用 scope 建立上下文，把挑选出的选项参数传入 scope 方法，并以此建立上下文，在建立的上下文中再次调用 resources 方法。其实质就是，RESOURCE_OPTIONS 之中的选项参数只会影响该 Resource，而不会传入上下文环境中，因为一旦传入上下文，那么就会在后续的上下文中产生某种全局影响，这样就会让 resource 相对独立，聪明的读者很快就会看出问题，等等这样的话，resources 怎么实现嵌套，呵呵，resources 有自己简单的机制来嵌套，后续会详细介绍。&lt;/p&gt;
&lt;h3 id="resources方法："&gt;resources 方法：&lt;/h3&gt;
&lt;p&gt;resources 方法恐怕是利用率最高的方法，如前文所述，不用人工干预就会产生八条路由和 4 个 helper，简单实用。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_options!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dup&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;apply_common_behavior_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:resources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;resource_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:resources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;block_given?&lt;/span&gt;
    &lt;span class="n"&gt;concerns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:concerns&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:concerns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;get&lt;/span&gt;  &lt;span class="ss"&gt;:index&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parent_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="ss"&gt;:create&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parent_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:new&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parent_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;set_member_mappings_for_resource&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;apply_common_behavior_for&lt;/code&gt; 方法就不要详细介绍，该方法非常重要，起到承上启下的作用，但由于篇幅原因，代码就不列出，他的主要功能就是进行递归调用，和一些参数的预处理，如果你传人多个实体资源，那么他会进行递归调用，如果设置 shallow: true，那么会先调用 shallow 方法建立 shallow 上下文；如果是 resources 嵌套调用，那么会建立 nested 上下文；如前文所讲，如果传入非 &lt;code&gt;RESOURCE_OPTIONS&lt;/code&gt;参数，就会建立包含这些选项的上下文， &lt;strong&gt;无论建立哪种上下文，都会在该上下文中再次递归调用 resources&lt;/strong&gt;。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;with_scope_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope.new_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="k"&gt;yield&lt;/span&gt;
&lt;span class="k"&gt;ensure&lt;/span&gt;
  &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope.parent&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resource_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shallow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope.new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:scope_level_resource&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@nesting.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;with_scope_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource_scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;ensure&lt;/span&gt;
  &lt;span class="vi"&gt;@nesting.pop&lt;/span&gt;
  &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope.parent&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;with_scope_level&lt;/code&gt; 函数，通过前面 Scope 的介绍，应该非常清楚，就是建立一个某种特殊的上下文，如 resources，nested，collection 等，但同时要注意它实现了堆栈操作，这就可以简单实现嵌套调用，嵌套调用本身就是先建立新环境，运行该环境下的代码，代码执行完成后恢复现场，也就是弹出堆栈，此种设计在路由映射中无处不在。resource_scope 函数代码简单，但是逻辑却不简单，算是一个核心函数。注意前文的 resources 方法在调用 resource_scope 时候，传了两个参数，一个是符号，代表的是某种 scope_level，另一个是 Resource 对象，各位看官，要注意了， &lt;strong&gt;传给 resources 方法的 options（经过筛选后的）是传给了 Resource 的构造函数，而不是传给了 scope，也就是说这些 options 只会影响 Resource 对象&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;source_scope&lt;/code&gt;函数首先判断 shallow 选项，在 new 一个上下文，仅仅设置 :scope_level_resource 的值，该值非常重要，通过他来访问当前上下文中的 parent_resource，来判断是不是处于 resources 中的嵌套调用，注意不是父级 scope，而是 Resource 对象，在 resources 嵌套调用中起到承上启下的作用，然后压入&lt;code&gt;@nesting&lt;/code&gt;，该值主要用来判断是否是在 resources 嵌套中。通过 with_scope_level 建立新的:resources 上下文，在:resources 上下文中，执行&lt;code&gt;scope(parent_resource.resource_scope)&lt;/code&gt;，parent_resource 就是刚刚传进来的 Resource 对象，该对象的 resource_scope 为&lt;code&gt;{:controller =&amp;gt; controller}&lt;/code&gt;，controller 函数返回的是 opintons[:controller] 或者实体资源的名字，这就建立了一个明确指定 :controller 的上下文，而在该 resource 上下文中执行诸如 collection, member 等上下文时，如果不明确指定 :controller，那么都是默认的实体资源对应的 controller，同样具有压栈出栈设计。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Source_scope&lt;/code&gt;函数返回到 resources 方法中，通过 &lt;code&gt;resource_scope&lt;/code&gt; 函数建立好 resources 上下文，并在该上下文中执行 block，通过 block 来实现嵌套调用，完成所有嵌套调用后再执行后面的代码。从此可以分析出，任何层级的嵌套调用都可以，并且执行顺序都是最内层的先执行，然后逐级恢复上下文执行该上下文的配置定义，最后在执行顶层（root 上下文的子级上下文）的配置，这样就有很好的隔离作用，就是只有父级影响子孙级，而子级不能影响父级。&lt;/p&gt;

&lt;p&gt;紧接着调用 concerns 方法，concern 和 concerns 其实非常简单，concern  字面意思，好像非常高大上，其实就是定义一个 callable，并注册到全局&lt;code&gt;@concerns&lt;/code&gt;中，在 Ruby 语言中，callable 可以是一个 block（实质是一个匿名 Proc 对象）、Proc、Lamda、Method、一个有 call 实例方法的对象或有 call 类方法的类；concerns 就是一个调用，根据名字在&lt;code&gt;@concerns&lt;/code&gt;查找，然后 call 调用 callable，具体产生什么结果，就是根据 callable 的定义和执行 concerns 的上下文来决定的。&lt;/p&gt;

&lt;p&gt;接下来调用 collection 方法，先忽略 shallow，shallow 后续详细介绍，建立一个 resource 上下文的子级 collection 上下文，然后执行配置定义，这里执行两个方法：get :index, post :create。&lt;/p&gt;

&lt;p&gt;先简单介绍一下 HttpHelpers 模块，该模块定义 5 个方法：get, post, patch, put, delete。五个方法都是通过&lt;code&gt;map_method&lt;/code&gt;实现：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;map_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_options!&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:via&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;
  &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每个函数传递一个 HTTP method，通过 :via 选项，传递给 match 函数，来实现一条路由映射，match 函数后续会详细介绍。&lt;/p&gt;

&lt;p&gt;new, member 与 collection 一样都是在当前 resource 上下文中建立各自的上下文，再执行相应的配置。&lt;/p&gt;

&lt;p&gt;new, member 与 collection 一样都是在当前 resource 上下文中建立各自的上下文，再执行相应的配置。现在让我们看看八条路由怎么产生，collection 上下文中，也就是集合路由生成两条 index, create，new 上下文中，生成一条路由 new，member 上下文中，生成五条成员路由（通过函数&lt;code&gt;set_member_mappings_for_resource&lt;/code&gt;）：edit, show, update(PUT), update(PATCH) ,  destroy，其中 update 有两条路由映射，路径和名称都相同，仅仅是 HTTP Method 不一样，分别是 PUT 和 PATCH。至此，八条路由映射全部生成。&lt;/p&gt;
&lt;h3 id="match方法："&gt;match 方法：&lt;/h3&gt;
&lt;p&gt;match 方法是路由映射核心函数之一，任何路由映射都由 match 方法来完成，那有朋友就会问，既然如此，何不直接介绍 match 方法，我一再强调，Rails 的路由映射中，任何一个方法都不能单独去解析，否则你会得到错误的结论，因为他们都是在不同的上下文中执行，所以都必须在某个上下文中去分析才会得到正确的结论，简单方法如 root、get 等，他们在不同的上下文中都会得到不同的 path 和 name。
match 方法的核心功能就是路由映射，既然是路由映射，那么就需要分析出:path 和:to，如果是命名路由，还需分析出 :name。我们来看看 match 定义：
def match(path, *rest)
根据定义，参数有两种情况，一种是传进来的 path 是一个 Hash，那么他会分析该哈希表，把第一个 key 是字符串类型的键值对当作:path 和:to（这里算不算是一个陷阱呢），同时对于:to 又有四种情况，:to 是一个符号，options[:action] = :to;  :to 是一个字符串，并且符合’xxx#xxx’，options[:to] = :to;  to 是一个字符串不符合’xxx#xxx’，options[:controller] = :to; :to 既不是符号也不是字符串，options[:to] = :to。另外一种是传进来一个或多个 path，加上一个哈希表，最后把分析好的 path 放到一个数组中。Path 数组分析好后，对每一个 path 根据 options 选项和上下文来分析最终路径和名称，还需注意的是，path 是符号还是字符串，也是有些许不同的，如果是符号且是 Resource 标准 action，并且没有设置 options[:path] 的情况下，最终路径为 &lt;code&gt;@scope[:path].to_s&lt;/code&gt;；如果是一个字符串，会覆盖 options[:path] 的值，最终路径为&lt;code&gt;#{@scope[:path]}/#{action_path(action, path)}&lt;/code&gt;。从这里也可以看出，不同的 path 可以映射到相同的目标。
match 方法最终会为每个 path 调用 &lt;code&gt;add_route&lt;/code&gt;函数，&lt;code&gt;add_route&lt;/code&gt;会调用&lt;code&gt;path_for_action&lt;/code&gt;和&lt;code&gt;name_for_action&lt;/code&gt;两个函数来生成最终的路径和名称，这两个函数非常关键，但是只要真正理解了上下文环境，那么他们就非常简单，只是简单的拼装和连接。有了路径和名称后就调用 Mapping.build 函数生成一路由映射，有了映射，就需要把该映射加入 (通过 RouteSet 对象的 add_route 方法) 到 RouteSet 对象中，至此，一个路由映射就全部完成。&lt;/p&gt;
&lt;h3 id="shallow方法："&gt;shallow 方法：&lt;/h3&gt;
&lt;p&gt;要开启 shallow，有两种方法，一是显式调用 shallow 方法，二是显式设置选项属性：&lt;code&gt;shallow:true&lt;/code&gt;。两个方法实质都是一样，因为 shallow 仅仅生成一个 &lt;code&gt;shallow:true&lt;/code&gt;的上下文，shallow 是有继承性质的，只要子上下文不显式关掉，那么就一直有效的。需注意的是，虽然每个配置方法都可以设置 shallow 属性，但是真正有效只有在 resources 和 resource 这两个上下文中，并不是说只能在 resource 和 resources 方法中设置，而是只有这两个会被 shallow 属性影响。在分析实现之前，来看看&lt;code&gt;shallow_scope&lt;/code&gt;函数定义：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;shallow_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; 
  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow_prefix&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="ss"&gt;:path&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow_path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope.new&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;
  &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;ensure&lt;/span&gt;
  &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@scope.parent&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是不是眼熟阿，前面介绍了 &lt;code&gt;resource_scope&lt;/code&gt;，原理都一样，&lt;code&gt;resource_scope&lt;/code&gt;建立一个 resource 上下文，&lt;code&gt;shallow_scope&lt;/code&gt;建立一个 shallow 上下文，非常简单，设置了 :as 和 :path 选项属性，shallow 的秘密就在此，想象一下，如果没有 shallow 的话，:path 会在 scope 时做&lt;code&gt;#{parent}/#{child}&lt;/code&gt;拼接，:as 会执行&lt;code&gt;#{parent}_#{child}&lt;/code&gt;拼接，这样就使在嵌套环境中，一层一层传递下去。Shallow 的目的是什么，是缩短路径和名称，shallow_scope 就是截断了：:as 和:path 的传递，指向了固定的值，就是把当前上下文&lt;code&gt;@scope[:as]&lt;/code&gt;和&lt;code&gt;@scope[:path]&lt;/code&gt;设为固定值，就无法向下传递了。&lt;/p&gt;
&lt;h4 id="范例："&gt;范例：&lt;/h4&gt;
&lt;p&gt;如果能一下就看出下面两个例子的区别并知道为什么，那么就不需要往下看了，因为你已经是专家了。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;shallow: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="ss"&gt;:'store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as: &lt;/span&gt;&lt;span class="s1"&gt;'sekret'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:books&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:dirs&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:pages&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;shallow: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;shallow_path: &lt;/span&gt;&lt;span class="s1"&gt;'store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;shallow_frefix: &lt;/span&gt;&lt;span class="s1"&gt;'sekret'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt;  &lt;span class="ss"&gt;:books&lt;/span&gt;  &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt;  &lt;span class="ss"&gt;:dirs&lt;/span&gt;  &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:pages&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两者都会生成总共 24 条路由和 12 个路由 helper，都有 shallow 属性，会生成短路径和名称，我们来看看结果，这里只分析路径和名称：&lt;/p&gt;
&lt;h5 id="第一个例子结果："&gt;第一个例子结果：&lt;/h5&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Prefix&lt;/span&gt; &lt;span class="no"&gt;Verb&lt;/span&gt;   &lt;span class="no"&gt;URI&lt;/span&gt; &lt;span class="no"&gt;Pattern&lt;/span&gt;                              &lt;span class="no"&gt;Controller&lt;/span&gt;&lt;span class="c1"&gt;#Action&lt;/span&gt;
   &lt;span class="n"&gt;sekret_dir_pages&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:dir_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#index&lt;/span&gt;
                    &lt;span class="no"&gt;POST&lt;/span&gt;   &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:dir_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#create&lt;/span&gt;
&lt;span class="n"&gt;new_sekret_dir_page&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:dir_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#new&lt;/span&gt;
   &lt;span class="n"&gt;edit_sekret_page&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#edit&lt;/span&gt;
        &lt;span class="n"&gt;sekret_page&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#show&lt;/span&gt;
                    &lt;span class="no"&gt;PATCH&lt;/span&gt;  &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;PUT&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;DELETE&lt;/span&gt; &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#destroy&lt;/span&gt;
   &lt;span class="n"&gt;sekret_book_dirs&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:book_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#index&lt;/span&gt;
                    &lt;span class="no"&gt;POST&lt;/span&gt;   &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:book_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#create&lt;/span&gt;
&lt;span class="n"&gt;new_sekret_book_dir&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:book_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#new&lt;/span&gt;
    &lt;span class="n"&gt;edit_sekret_dir&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#edit&lt;/span&gt;
         &lt;span class="n"&gt;sekret_dir&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#show&lt;/span&gt;
                    &lt;span class="no"&gt;PATCH&lt;/span&gt;  &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;PUT&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;DELETE&lt;/span&gt; &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#destroy&lt;/span&gt;
       &lt;span class="n"&gt;sekret_books&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#index&lt;/span&gt;
                    &lt;span class="no"&gt;POST&lt;/span&gt;   &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#create&lt;/span&gt;
    &lt;span class="n"&gt;new_sekret_book&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#new&lt;/span&gt;
   &lt;span class="n"&gt;edit_sekret_book&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#edit&lt;/span&gt;
        &lt;span class="n"&gt;sekret_book&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#show&lt;/span&gt;
                    &lt;span class="no"&gt;PATCH&lt;/span&gt;  &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;PUT&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;DELETE&lt;/span&gt; &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#destroy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="第二个例子结果："&gt;第二个例子结果：&lt;/h5&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt; &lt;span class="no"&gt;Prefix&lt;/span&gt; &lt;span class="no"&gt;Verb&lt;/span&gt;   &lt;span class="no"&gt;URI&lt;/span&gt; &lt;span class="no"&gt;Pattern&lt;/span&gt;                              &lt;span class="no"&gt;Controller&lt;/span&gt;&lt;span class="c1"&gt;#Action&lt;/span&gt;
   &lt;span class="n"&gt;sekret_dir_pages&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:dir_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#index&lt;/span&gt;
                    &lt;span class="no"&gt;POST&lt;/span&gt;   &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:dir_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#create&lt;/span&gt;
&lt;span class="n"&gt;new_sekret_dir_page&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:dir_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#new&lt;/span&gt;
   &lt;span class="n"&gt;edit_sekret_page&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#edit&lt;/span&gt;
        &lt;span class="n"&gt;sekret_page&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#show&lt;/span&gt;
                    &lt;span class="no"&gt;PATCH&lt;/span&gt;  &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;PUT&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;DELETE&lt;/span&gt; &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="c1"&gt;#destroy&lt;/span&gt;
   &lt;span class="n"&gt;sekret_book_dirs&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:book_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#index&lt;/span&gt;
                    &lt;span class="no"&gt;POST&lt;/span&gt;   &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:book_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#create&lt;/span&gt;
&lt;span class="n"&gt;new_sekret_book_dir&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:book_id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#new&lt;/span&gt;
    &lt;span class="n"&gt;edit_sekret_dir&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#edit&lt;/span&gt;
         &lt;span class="n"&gt;sekret_dir&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#show&lt;/span&gt;
                    &lt;span class="no"&gt;PATCH&lt;/span&gt;  &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;PUT&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;DELETE&lt;/span&gt; &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="c1"&gt;#destroy&lt;/span&gt;
              &lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/books(.:format)                         books#index
                    POST   /&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                         &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#create&lt;/span&gt;
           &lt;span class="n"&gt;new_book&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/books/ne&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                     &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#new&lt;/span&gt;
   &lt;span class="n"&gt;edit_sekret_book&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#edit&lt;/span&gt;
        &lt;span class="n"&gt;sekret_book&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#show&lt;/span&gt;
                    &lt;span class="no"&gt;PATCH&lt;/span&gt;  &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;PUT&lt;/span&gt;    &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#update&lt;/span&gt;
                    &lt;span class="no"&gt;DELETE&lt;/span&gt; &lt;span class="sr"&gt;/store/&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="c1"&gt;#destroy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现差别没有，与我们想象的不太一样，第一个例子 scope 传了 path 和 as 参数，按照一般理解，在&lt;code&gt;shallow_scope&lt;/code&gt;时，会执行以下两条语句，覆盖 path 和 as:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow_prefix&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="ss"&gt;:path&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow_path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为什么没有被覆盖呢，我们返回去看看 scope 方法，发现一段代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;nested_scope?&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow_path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:shallow_prefix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原来如此，在这里对&lt;code&gt;shallow_path&lt;/code&gt;和&lt;code&gt;shallow_prefix&lt;/code&gt;赋值，为什么要这么做，前面有讲过，shallow 只会影响 resources 和 resource 上下文，我个人理解是为了在 shallow 上下文中保留 resources 之前的上下文环境。&lt;/p&gt;

&lt;p&gt;第二个例子就相对比较简单，基本上是按照我们的理解来实现的，但是要注意一点，就是顶层的 resources，在 collection 上下文处理集合路由时，是不需要在 shallow 上下文中进行，因为如果在嵌套中集合成员必须要父级的&lt;code&gt;member_id&lt;/code&gt;才能正确识别路由，所以对于顶层 resources，集合成员路由与在非 shallow 环境中一样。&lt;/p&gt;
&lt;h3 id="resources 嵌套实现:"&gt;resources 嵌套实现：&lt;/h3&gt;
&lt;p&gt;在理解了上下文关系后，再来分析就非常简单，程序通过&lt;code&gt;parent_resource&lt;/code&gt;自动判断出是否是处于嵌套中，如果处于嵌套中就会建立嵌套上下文环境。nested 方法就是用来建立 nested 上下文的，方法简单，再次证明只有理解了上下文的含义，一切都很简单。在 nested 方法中，通过如下一条语句来实现：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nested_scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nested_options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;path 是&lt;code&gt;parent_resource&lt;/code&gt;的&lt;code&gt;nested_scope&lt;/code&gt;，如上文所述，&lt;code&gt;nested_scope: #{path}/:#{nested_param}&lt;/code&gt;，这就解决了路径的嵌套，名字嵌套怎么解决呢，还有一个 &lt;code&gt;nested_options&lt;/code&gt;，该函数通过语句
&lt;code&gt;options = { :as =&amp;gt; parent_resource.member_name }&lt;/code&gt; 设置了 &lt;code&gt;member_name&lt;/code&gt;，实现了名称的嵌套。&lt;/p&gt;
&lt;h3 id="Mapping:"&gt;Mapping:&lt;/h3&gt;
&lt;p&gt;前面有介绍，每一条路由都对应有一个 Mapping 对象，都是通过 &lt;code&gt;Mapping.build&lt;/code&gt; 建立的 Mapping 对象。在 match 方法中，主要负责分析最终路径和名称，还有一个目标的问题没有解决，Rails 中把目标简称为 app，Mapping 主要功能就是把目标包装成一个 app，这个 app 并不是 Rack app，严格来说是一个 Dispatcher，就是具有 serve(req) 实例方法的类。&lt;/p&gt;

&lt;p&gt;Mapping 有几个核心功能，根据传进来的&lt;code&gt;@scope&lt;/code&gt;上下文和 options，分析出 app, conditions, requirements, defaults, blocks，这些参数最终会传给 Journey::Router，来完成路由映射。&lt;/p&gt;

&lt;p&gt;首先来分析目标，目标有两种表现形式，一是目标本身是一个 Rack base app 或更广泛的定义，能够响应 call 函数的对象，如果是这种 app，直接赋值给:to;  二是分别设置:controller 和:action。Mapping.build 传进来的也是:to, :controller, :action，三个参数，如果传入参数是:to，那么会分为两种情况：一种是 Rack base app，另一种是’xxx#xxx’，前一种直接传给:to，后一种需要转变成 :controller 和 :action。处理好这些后，分别对:controller 和:action 进行模块设定和有效性检查。&lt;/p&gt;

&lt;p&gt;现在所有 options 都已准备就绪，需要进一步分离，分离的大致步骤是：首先对&lt;code&gt;@scope[:constraints]&lt;/code&gt;进行分析，如果 key 是：controller 或在 path_params 中，并且是正则表达式，就放入 requirements 中，否则放入 conditions, 接着对 options 进行筛选把所有正则表达式筛选出来做进一步分析，其它没有包含 path_params 中的全部放入 &lt;code&gt;conditions[:required_defaults]&lt;/code&gt;中；再对刚刚筛选出来进一步分析，如果 key 是：controller 或在 path_params 中，并且是正则表达式，就放入 requirements 中，其它则放入 conditions；最后对 defaults 进行处理，先对 URL_OPTIONS 中的 key 进行初始化赋值，再对 options 进行扫描，非正则表达式全部放入 defaults 中，至此就把所有 options 全部分离为 requirements, conditions, defaults。&lt;/p&gt;

&lt;p&gt;blocks 仅仅对 options[:constraints] 进行分析，如果不是哈希表，并且是一个 callable 或 matches 对象，那么把该对象赋值给 blocks，否则把&lt;code&gt;@scope[:blocks]&lt;/code&gt;赋值给 blocks。&lt;/p&gt;

&lt;p&gt;blocks 虽然分析出来了，可能有些朋友还不是很清楚，blocks 到底是什么，简单说每一个 block 都是一个限制条件。Rails 路由限制条件有三种形式：一是正则表达式，如&lt;code&gt;id: /[A-Z]\d{5}/&lt;/code&gt;；二是任何&lt;code&gt;responds to matches?&lt;/code&gt; 为 true 的对象，如:String, Array, Range, CustomMatches 等；三是 callable 对象，如 Proc, Lamda, Method, respond_to call Object。&lt;/p&gt;

&lt;p&gt;根据分析，:constraints 和:blocks 都是某种条件限定，就是说只有满足所有限定条件，才会执行目标程序，按源代码分析，限定条件可以在两个地方执行，一是 Journey::Router 识别的时候，另一个是在目标 app 执行，目标 app 优先执行:constraints 的 callable 或 matches 对象的限定条件，其它都放在识别的时候。&lt;/p&gt;

&lt;p&gt;Mapping 利用 app(blocks) 函数来封装一个 app，如果:to 是 callable 对象，用:to 和 blocks 封装成一个 Constraints 对象，该对象是一个有限定条件的 Endpoint；如果:to 不是 callable，并且 blocks 不为空，用 blocks 封装成一个 Constraints, 该对象封装了一个有限定条件的 Dispatcher；如果:to 不是 callable，并且 blocks 为空，那么仅仅简单用缺省条件封装成一个 Dispatcher。&lt;/p&gt;

&lt;p&gt;至此，app, conditions, requirements, defaults, as 都有了，就可以把它添加到 RouteSet 了。&lt;/p&gt;

&lt;p&gt;路由映射部分已基本完成，其它未完待续。&lt;/p&gt;</description>
      <author>gerry</author>
      <pubDate>Mon, 17 Nov 2014 23:11:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/22726</link>
      <guid>https://ruby-china.org/topics/22726</guid>
    </item>
  </channel>
</rss>
