Routing 概述:生成、存储、识别
描述
- DSL --> Mapper(Base, Concerns, HttpHelpers, Resources, Scoping) 
- 既然维护着一张路由表,如何向表里添加规则? 
- 外部的 url 是如何识别并处理的?先预处理,然后对照路由表,然后转发给 Controller#action,再接下来就是我们熟悉的东西了。 
- 路由分类具名路由 和 匿名路由,内部可以调用具名路由(不调用,它就没意义了)。那么这些方法在哪定义的? 
- Rails 引入了 engine 的概念,涉及到 engine 的路由表是如何工作的? - 注意上面描述里的动词 
1) 里对应着 mapper.rb 文件,及里面的各个子模块。
2) 由 add_route 完成,涉及一大堆的东西。
3) 里的转发给 Controller#action 这部分,由 Dispatcher 完成。通过 controller.action(action).call(env),到具体的 Controller & action -- 常见的 rack 用法。
4) 里的定义方法,由 Named Route Collection 完成。它还代表了具名路由。
def define_url_helper(route, name, options)
  helper = UrlHelper.create(route, options.dup)
  @module.remove_possible_method name
  @module.module_eval do
    define_method(name) do |*args|
      helper.call self, args
    end
  end
  helpers << name
end
def define_named_route_methods(name, route)
  define_url_helper route, :"#{name}_path",
    route.defaults.merge(:use_route => name, :only_path => true)
  define_url_helper route, :"#{name}_url",
    route.defaults.merge(:use_route => name, :only_path => false)
end4) 内部调用并不一定总是通过 具体路由进行调用,例如:有时候我们会使用 link_to @record ... 这种情况,极端情况下会由路由这边生成 url,由 Generator 完成。
5) 涉及 engine 的路由部分,由 Mounted Helpers 完成。
Journey 就是个打杂的,其它看得见和看不见的功能由它负责。
路由的生成、存储、识别
1) 路由对象的定义和调用方式:
# 定义
module Rails
  class Engine < Railtie
    def routes
      @routes ||= ActionDispatch::Routing::RouteSet.new
      @routes.append(&Proc.new) if block_given? # 调用时,也可以追加路由规则
      @routes
    end
  end
end
# 调用方式
Rails.application.routes
Rails.application.routes { ... }2) 调用路由对象,生成路由规则:
Rails.application.routes.draw do
  # ... block 内容
end3) 生成路由规则,本质是对 block 内容的求值:
def draw(&block)
  # ...
  eval_block(block)
  # ...
  nil
end4) 怎么求值呢?借助了 Mapper 的实例对象:
def eval_block(block)
  # ...
  mapper = Mapper.new(self)
  # ...
  mapper.instance_exec(&block)
end5) Mapper 的实例对象有什么内容?
module ActionDispatch
  module Routing
    class Mapper
      # 这里 set = Rails.application.routes
      def initialize(set)
        @set = set
        @scope = Scope.new({ :path_names => @set.resources_path_names })
        @concerns = {}
        @nesting = []
      end
    end
  end
end6) Mapper 实例对象有了,下一步就是执行 instance_exec. 也就是运行 block 里的各个方法。
7) block 里的各个方法,是在 Mapper 下面的各个模块里定义的:
module ActionDispatch
  module Routing
    class Mapper
      # ...
      class Constraints < Endpoint
        # ...
      end
      class Mapping
        # ...
      end
      class Scope
        # ...
      end
      # ... 下面的各个模块
      module Base
        # ...
      end
      module HttpHelpers
        # ...
      end
      module Redirection
        # ...
      end
      module Scoping
        # ...
      end
      module Concerns
        # ...
      end
      module Resources
        # ...
      end
      include Base
      include HttpHelpers
      include Redirection
      include Scoping
      include Concerns
      include Resources
    end
  end
end在这里,不同的路由规则会有对应的模块进行处理,具体可以在对应的各个章节查看。
8) 附:Mapper 的 ancestors
ActionDispatch::Routing::Mapper.ancestors
=> [ActionDispatch::Routing::Mapper,
 ActionDispatch::Routing::Mapper::Resources,
 ActionDispatch::Routing::Mapper::Concerns,
 ActionDispatch::Routing::Mapper::Scoping,
 ActionDispatch::Routing::Redirection,
 ActionDispatch::Routing::Mapper::HttpHelpers,
 ActionDispatch::Routing::Mapper::Base,
 # ...,
 ...]最后更新于
这有帮助吗?