# 实例对象和各个实例方法

## 实例对象

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

```ruby
# 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 里：

```ruby
# 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)
```

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

```ruby
# 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
```

## 各个实例方法

```ruby
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` 使用举例：

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

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

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

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

相关代码：

```ruby
mapper = Mapper.new(self)

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

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

`initialize`用到了 NamedRouteCollection， 内容是：

```ruby
self.named_routes = NamedRouteCollection.new
```

初始化了几个有意义的变量，如：named\_routes、@set、@router、@formatter

`generate` 用到了 Generator，内容是：

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

`dispatcher` 用到了 Dispatcher 内容是：

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kelby.gitbook.io/rails-beginner-s-guide/actiondispatch_routeset/routeset.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
