实例对象和各个实例方法

实例对象

在 Rails 源代码里,app.routes 指的是 RouteSet 的实例对象。

# action_mailer/railtie.rb
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes, false)
include app.routes.mounted_helpers

# action_controller/railtie.rb
include app.routes.mounted_helpers
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)

# action_dispatch/routing/mapper.rb
app.routes.define_mounted_helper(name)
app.routes.extend Module.new { ... }

# rails/application/finisher.rb
app.routes.append do ... end
app.routes.define_mounted_helper(:main_app)

在 Rails 源代码里,@set 有时候也是 RouteSet 的实例对象,如 Mapper 里:

# action_dispatch/routing/mapper.rb
initialize
  @set = set
  @scope = Scope.new({ :path_names => @set.resources_path_names })

dispatcher
  @set.dispatcher defaults

default_url_options=
  @set.default_url_options = options

has_named_route?
  @set.named_routes.routes[name.to_sym]

define_generate_prefix
  _route = @set.named_routes.get name
  _routes = @set

add_route
  mapping = Mapping.build(@scope, @set, URI.parser.escape(path), as, options)
  @set.add_route(app, conditions, requirements, defaults, as, anchor)

name_for_action
  candidate unless candidate !~ /\A[_a-z]/i || @set.named_routes.key?(candidate)

也正因为如此,除了 drawadd_routes 外,我们可以在代码里搜索,看哪里的代码影响了路由规则的生成。

# route_set.rb
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
attr_accessor :disable_clear_and_finalize, :resources_path_names
attr_accessor :default_url_options, :request_class

alias :routes :set

# formatter 是 Journey::Formatter 的实例对象
# set 是 Journey::Routes 的实例对象
# named_routes 是 NamedRouteCollection 的实例对象
# router 是 Journey::Router 的实例对象
# resources_path_names 也就是 default_resources_path_names,默认有:new 和 edit
# request_class 默认是 ActionDispatch::Request

各个实例方法

inspect & to_s
routes & set

draw

# 往变量 @append 和 @prepend 里塞东西
append
prepend

finalize!

# 消除 named_routes、set、formatter
clear!

dispatcher

# 包含了所有 Engine 提供的 helper 方法,和 main_app 方法。
mounted_helpers

# 新增 Engine 提供的 helper 方法。
# 用到了 MountedHelpers 和 RoutesProxy
define_mounted_helper

# 它其它是一个 Module
# 所以我们可以 include Rails.application.routes.url_helpers
# 包含了所有和 URL 有关的 helper 方法(也就是所有 x_url 和 x_path 方法)。
url_helpers

# 没有路由规则?
empty?

# 会调用到以下方法:
# build_path
# build_conditions
# @set.add_route
# named_routes[name]
add_route

extra_keys
generate_extras

# generate_extras 和 url_for 调用到
generate

# 我们在路由规则是可以带默认参数的,这在定义的时候就可以知道。
# 这里的意思其实是:有默认参数吗?
optimize_routes_generation?

find_script_name # url_for 调用到

# 可谓是其它组件 url_for 方法的源头
# (当然,得用到路由方法才行)
url_for
path_for # 简单封装 url_for

# 浏览器里输入的网址,最先经过它解析
# 关键部分是调用 @router.recognize
recognize_path

recognize_path 使用举例:

Rails.application.routes.recognize_path "http://localhost:3000/users/1"
# => {:controller=>"users", :action=>"show", :id=>"1"}

通过这一步,外部 URL 已经被转换成了 Rails 能够识别的语言。在这之后,Rails 想怎么处理就怎么处理。

# 使用 Journey 处理我们提供的路由规则,得到 path 这部分
build_path

draw 直接对外暴露的接口,初始化 Mapper 对象。然后交还各个模块处理。 本质是:运用 Mapper,处理 config/routes.rb 里的代码。

相关代码:

mapper = Mapper.new(self)

if default_scope
  mapper.with_default_scope(default_scope, &block)
else
  mapper.instance_exec(&block)
end

之后,就是执行【路由常用方法汇总】章节里提到的方法。

initialize用到了 NamedRouteCollection, 内容是:

self.named_routes = NamedRouteCollection.new

初始化了几个有意义的变量,如:named_routes、@set、@router、@formatter

generate 用到了 Generator,内容是:

Generator.new(route_key, options, recall, self).generate

dispatcher 用到了 Dispatcher 内容是:

Routing::RouteSet::Dispatcher.new(defaults)

最后更新于