新建 Rails 应用
(发布于 2013 年 5 月 12 日)
本文针对 Rails 4。
新建 Rails 应用的第一步是,在命令行中执行 rails new
命令。执行这个命令后到底发生了什么?
当我们在命令行中输入 rails new [PATH]
后,命令行先要找到 rails
这个可执行文件,可以使用 which
命令查看,具体的路径视安装方式而不同。我使用 rbenv
管理 Ruby,所以在我的电脑中,rails
可执行文件的位置在 ~/username/.rbenv/shims/rails
。
rails
这个可执行文件就是 railties/bin/rails
,内容很简单:
#!/usr/bin/env ruby
git_path = File.join(File.expand_path('../../..', __FILE__), '.git')
if File.exists?(git_path)
railties_path = File.expand_path('../../lib', __FILE__)
$:.unshift(railties_path)
end
require "rails/cli"
第一行是 shebang 声明,其他几行暂且不提,最后一行才是关键,把命令的实现交由 railties/lib/rails/cli.rb
(source)。railties/lib/rails/cli.rb
第 6 行,调用 Rails::AppRailsLoader.exec_app_rails
方法,在 railties/lib/rails/app_rails_loader.rb
中定义(source)。
exec_app_rails
这个类方法执行一个 loop
无限循环,直到在当前工作目录或上层目录中找到 bin/rails
这个可执行文件为止。这个方法的作用是判断 pwd 或上层目录是否为 Rails 应用目录,如果是一个现有的 Rails 应用,则终止执行 railties/lib/rails/cli.rb
的后续内容。
现在,假设我们的 pwd 不是既有 Rails 应用目录,执行 rails new [PATH]
命令,则会跳到 railties/lib/rails/cli.rb
的第 8 行,,判断 Ruby 的版本,如果小于 1.9.3,便终止命令。Rails 4 推荐使用 Ruby 2.0。
railties/lib/rails/cli.rb
第 11-16 行,是 if-else
分支语句,跳过 if
分支,直接看 else
分支,加载 railties/lib/rails/commands/application.rb
(souece)。这个文件第 3-6 行不会在执行 rails new
命令是运行,暂且不提。接下来又是一个 if-else
分支,直接看 else
分支。
如果在执行 rails new
命令时没有指定 --no-rc
选项的话,会执行第 12-25 行,读取 ~/.railsrc
文件。
然后,加载所需的生成器文件:
require 'rails/generators'
require 'rails/generators/rails/app/app_generator'
第 43 行,才是关键,Rails::Generators::AppGenerator.start
。
Rails 的生成器是通过 Thor 实现的。Rails::Generators::AppGenerator
的父类如下:Rails::Generators::AppBase < Rails::Generators::Base < ::Thor::Group
。Thor::Group
的用法可以参考 Thor 的 Wiki,简单来说,Group 中定义的实例方法,会按照顺序执行,特别适合用来生成文件。
调用 Rails::Generators::AppGenerator.start
方法后,会按照顺序调用如下方法: create_root
,create_root_files
,create_app_files
,create_bin_files
,create_config_files
,create_boot_file
,create_active_record_files
,create_db_files
,create_lib_files
,create_log_files
,create_public_files
,create_test_files
,create_tmp_files
,create_vendor_files
,finish_template
。文件的模板位于 railties/lib/rails/generators/rails/app/templates/
目录下。
然后,我们在命令行中就看到了一串说明:
$ rails new demo -B
create
create README.rdoc
create Rakefile
create config.ru
create .gitignore
create Gemfile
create app
create app/assets/javascripts/application.js
create app/assets/stylesheets/application.css
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/views/layouts/application.html.erb
create app/mailers/.keep
create app/models/.keep
create app/controllers/concerns/.keep
create app/models/concerns/.keep
create bin
create bin/bundle
create bin/rails
create bin/rake
create config
create config/routes.rb
create config/application.rb
create config/environment.rb
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
create config/initializers
create config/initializers/backtrace_silencers.rb
create config/initializers/filter_parameter_logging.rb
create config/initializers/inflections.rb
create config/initializers/mime_types.rb
create config/initializers/secret_token.rb
create config/initializers/session_store.rb
create config/initializers/wrap_parameters.rb
create config/locales
create config/locales/en.yml
create config/boot.rb
create config/database.yml
create db
create db/seeds.rb
create lib
create lib/tasks
create lib/tasks/.keep
create lib/assets
create lib/assets/.keep
create log
create log/.keep
create public
create public/404.html
create public/422.html
create public/500.html
create public/favicon.ico
create public/robots.txt
create test/fixtures
create test/fixtures/.keep
create test/controllers
create test/controllers/.keep
create test/mailers
create test/mailers/.keep
create test/models
create test/models/.keep
create test/helpers
create test/helpers/.keep
create test/integration
create test/integration/.keep
create test/test_helper.rb
create tmp/cache
create tmp/cache/assets
create vendor/assets/javascripts
create vendor/assets/javascripts/.keep
create vendor/assets/stylesheets
create vendor/assets/stylesheets/.keep
最后,我们得到了一个 Rails 应用骨架。