Rails autoload_paths

之前的博客中提过 Ruby 中的常量查找以及 $LOAD_PATH。而在 Rails 中,又将这个步骤更加简化了。先来看一段 Rails 程序中常见的代码。在 app/controllers/ 中有一个 posts_controller.rb 文件

class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end

这段代码初看很简单,其实背后 Rails 帮我们做了很多事。比如 ApplicationControllerPost 这两个常量是哪里来的?为什么我们不需要去 require 它就可以直接使用了呢?

这就是因为 Rails 中有一个类似于 $LOAD_PATH 的东西去查找这些变量,它就是 autoload_paths。在 config/application.rb 文件中我们对它进行配置,config.autoload_paths += [...]。默认的情况下,Rails 的 autoload_paths 包括了以下目录

$ bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths'
.../app/assets
.../app/controllers
.../app/helpers
.../app/mailers
.../app/models
.../app/controllers/concerns
.../app/models/concerns
.../test/mailers/previews

那么下来来解决我们的问题,ApplicationControllerPost 这两个东西到底是怎么来的。

ApplicationController

为了加载 ApplicationController,Rails 会去遍历 autoload_paths。因此首先会去找 app/assets/application_controller.rb,不存在。再去找 app/controllers/application_controller.rb。bingo!接着 Rails 会去为我们加载这个文件。

Post

查找 post.rb 的过程会麻烦一些,因为是在 PostsController 中调用它。因此首先会把下面的目录遍历一次

app/assets/posts_controller/post
app/controllers/posts_controller/post
app/helpers/posts_controller/post
...
test/mailers/previews/posts_controller/post

查找无果,接着会去它的父命名空间去查找,在这里来说就是 top level 了。

app/assets/post.rb
app/controllers/post.rb
app/helpers/post.rb
app/mailers/post.rb
app/models/post.rb

最后我们会找到我们需要的 app/models/post.rb