首页
/ 深入解读 Rails 3.0 发行说明:Merb 融合带来的六项架构变革,以及它们在当前 Rails 代码库中的延续

深入解读 Rails 3.0 发行说明:Merb 融合带来的六项架构变革,以及它们在当前 Rails 代码库中的延续

2026-09-06 13:45:41作者:齐添朝

本篇基于 Rails 官方仓库中的历史发行说明文档 3_0_release_notes.md,完整还原 Rails 3.0 从 Rails 2.x 升级的全部关键路径:Ruby 版本要求、Application 对象、script/rails、Bundler 依赖管理、全新的 Action Dispatch 路由器、无侵入式 JavaScript(UJS)、validates 验证 API、基于 Arel 的可链式查询接口,以及基于 Mail gem 重写的 Action Mailer。读完本文,你既能掌握 Rails 3.0 发行说明的全部技术要点,也能顺藤摸瓜在当前 Rails 源码仓库中找到每一项架构决策的“后代”,理解现代 Rails 的骨架是如何在那次大重构中成形的。

一、Rails 3.0 的定位:Merb 团队融合后的“大解耦”

Rails 3.0 发行说明的开头即点明了它的来路:这是 Merb 团队加入 Rails 阵营后的第一个大版本,带来了“对框架无关性的关注、更精简快速的内部实现,以及一批令人愉悦的新 API”。来自 Merb 1.x 的开发者会发现大量熟悉的面孔,而从 Rails 2.x 升级的开发者同样能平滑过渡——因为团队刻意用完善的弃用警告(deprecation warnings)包裹了所有旧 API,使得存量应用不必立即重写就能跑在 Rails 3 上。

发行说明给出的五大亮点是:

  • 全新的路由器,强调 RESTful 声明式路由;
  • 新的 Action Mailer API,以 Action Controller 为范本重写,彻底摆脱发送 multipart 邮件的痛苦;
  • 新的 Active Record 可链式查询语言,构建在关系代数(Arel)之上;
  • 无侵入式 JavaScript 助手,配套 Prototype、jQuery 等驱动,宣告行内 JS 的终结;
  • 基于 Bundler 的显式依赖管理

从规模上看,Rails 3.0 由近 4,000 个提交、超过 250 位作者贡献完成。发行说明本身只覆盖主要升级点,逐条 bug 修复不在其列。

安装方式非常简单,一条命令即可:

# 如环境需要可加 sudo
$ gem install rails

从 Rails 2.x 升级的前提条件

发行说明给出了明确的升级路线图:先保证良好的测试覆盖 → 升级到 Rails 2.3.5 验证应用仍正常 → 再进入 Rails 3。具体要注意的变化如下。

1. 最低 Ruby 版本为 1.8.7

Rails 3.0 要求 Ruby 1.8.7 或更高,同时兼容 Ruby 1.9.2。发行说明附有一条重要的历史提示:

  • Ruby 1.8.7 p248/p249 存在序列化(marshalling)bug,会导致 Rails 3.0 崩溃(REe 1.8.7-2010.02 起已修复);
  • Ruby 1.9.1 在 Rails 3.0 上会直接段错误,不可用;想用 1.9.x 就选 1.9.2。

2. Rails Application 对象

为支持“同一进程中运行多个 Rails 应用”,Rails 3 引入了 Application 对象:它持有全部应用级配置,性质上相当于旧版 config/environment.rb。每个 Rails 应用都必须在 config/application.rb 中定义对应的应用对象;升级时需要新建该文件,并把 config/environment.rb 中的相应配置迁移过去。

3. script/*script/rails 取代

新的 script/rails 取代了 script 目录下的所有脚本,但它不直接执行——rails 命令检测到在应用根目录中被调用时,会自动转手执行对应脚本。惯用方式为:

$ rails console                      # 取代 script/console
$ rails g scaffold post title:string # 取代 script/generate scaffold post title:string

rails --help 可列出全部选项。

4. config.gem 退役,Bundler 接管

config.gem 方法被彻底移除,由 Bundler 加 Gemfile 取代(详见下文“Gemfile 与本地打包”)。

升级辅助工具:rails_upgrade 插件

发行说明推荐了官方的 rails_upgrade 插件来自动化升级流程。安装后运行 rake rails:upgrade:check 即可检查应用中需要更新的部分(并附更新指引);它还能根据现有 config.gem 调用生成 Gemfile,并根据现有路由文件生成新的 routes 文件:

$ ruby script/plugin install git://github.com/rails/rails_upgrade.git

二、创建 Rails 3.0 应用与 Gemfile 依赖管理

新建应用的标准姿势:

# 前提:已安装 rails RubyGem
$ rails new myapp
$ cd myapp

Gemfile 与本地打包(Vendoring Gems)

Rails 3 起,应用根目录的 Gemfile 决定了启动所需的全部 gem。该文件由 Bundler 处理并安装依赖,还可以把依赖全部安装到应用本地,使应用不再依赖系统级 gem。

这一改变直接淘汰了旧机制:既然可以用 bundle 命令把应用依赖“冻结”,rake freeze 便失去意义并被移除。发行说明提供了两个面向“追新”开发者的开关:

# 从 Git 仓库直接拉取 Rails 主干
$ rails new myapp --edge

# 使用本地的 Rails 检出目录生成应用
$ ruby /path/to/rails/bin/rails new myapp --dev

此外,应用生成器新增了若干跳过选项,可跳过 test-unit、Active Record、Prototype 和 Git 的安装。--dev 标志会让生成的 Gemfile 指向本地的 Rails 检出目录(由 rails 二进制的路径推断)。

三、六项重大架构变革

发行说明将 Rails 3 的架构变化归纳为六点。下面逐项展开,并对照当前仓库标注这些设计的落点。

1. Railties 重造(Restrung)

Railties 被更新为“整个 Rails 框架一致的插件 API”,同时彻底重写了生成器和 Rails 绑定。结果是:开发者可以在一致的、定义明确的方式下,挂接到生成器与应用框架的任何重要阶段。当前仓库中,这一层的实现位于 railties/lib/rails,其中包含 150 余个 Ruby 文件与 130 余个生成器模板,正是当年“生成器完全重写”之后的产物。

2. 核心组件全面解耦(The Great Decoupling)

Merb 与 Rails 合并后的大工程,就是拆除核心组件之间的紧耦合。达成之后,所有核心组件都使用与插件开发相同的 API——任何插件、任何核心组件替代品(如 DataMapper、Sequel)都能获得与核心组件同等的扩展能力。

3. Active Model 抽象层

解耦的一部分是把 Action Pack 对 Active Record 的所有依赖全部抽出。完成后,新 ORM 插件只需实现 Active Model 接口即可与 Action Pack 无缝协作。在当前仓库中,这一抽象层独立为 activemodel 组件,activemodel/lib/active_model 下可见 validations.rbtranslation.rbcallbacks.rbnaming.rb 等模块,其中 validator.rbvalidations 目录正是下文 validates 新 API 的实现所在。

4. AbstractController 控制器抽象

为了把“渲染视图”等行为从 HTTP 概念中剥离,Rails 3 创建了与 HTTP 无关的基类 AbstractController,使 ActionControllerActionMailer 得以大幅简化:公共代码被抽到 Abstract Controller 中,消除了各库间的重复。当前仓库中它位于 actionpack/lib/abstract_controllerbase.rbrendering.rbtranslation.rb 等模块即是当年抽象的直接延续。

5. Arel 集成

Arel(Active Relation)被纳入 Active Record 的底层并成为 Rails 的必需组件。它提供 SQL 抽象,简化了 Active Record 本体,并为 Active Record 的关系(relation)能力提供了基础。当前仓库中,Arel 作为 activerecord/lib/arel 目录完整保留,是查询接口可链式调度的执行引擎。

6. Mail 提取

Action Mailer 自诞生起就背着猴子补丁、预解析器、投递/接收代理,甚至在源码树里 vendored 了 TMail。Rails 3 将所有邮件消息相关功能抽象到独立的 Mail gem,减少了代码重复,并在 Action Mailer 与邮件解析器之间划出可定义的边界。这一决定的现代形态在 actionmailer/lib/action_mailer/base.rb 中依然清晰可见:ActionMailer::Baseinitialize 中直接 @_message = Mail.newbase.rb#L656),整个 Action Mailer 只是 Rails DSL 加 Mail gem 的封装。

四、Railties 的具体变化

解耦使 Railties 得到一次大手术,目标是让接入框架、引擎、插件尽可能无痛且可扩展:

  • 应用命名空间:每个应用拥有自己的命名空间,应用启动形如 YourAppName.boot,便于与其他应用共存交互;
  • Rails.root/app 全量加入加载路径:例如创建 app/observers/user_observer.rb 即可被自动加载,无需任何配置;
  • Rails.config 对象:Rails 3.0 起提供 Rails.config 作为全局配置的中心仓库。

生成器的彻底重写

Rails 3.0 中生成器受到的关注度极高,核心结论:

  • 生成器被完全重写,与旧版本不向后兼容;
  • 旧的 Rails 模板 API 与生成器 API 合并为同一套
  • 生成器不再从特殊路径加载,而是按 Ruby 加载路径查找——rails generate foo 会寻找 generators/foo_generator
  • 新生成器提供钩子(hooks),任何模板引擎、ORM、测试框架都能方便地挂接;
  • 支持模板覆盖:在 Rails.root/lib/templates 放一份副本即可替换生成模板;
  • 提供 Rails::Generators::TestCase 用于编写和测试自定义生成器。

当前仓库中,这一套体系演化成了 railties/lib/rails/generators 目录——本仓库中 rails newrails generate 等命令的所有模板与逻辑都源于这次重写。

生成视图与 rake 任务的改进

  • 生成的视图改用 div 标签,替代原来的 p 标签;
  • Scaffold 生成的页面开始使用 _form 局部模板,避免 new/edit 视图中的重复代码;
  • Scaffold 表单使用 f.submit,根据传入对象的状态自动输出 "Create ModelName" 或 "Update ModelName"。

rake 任务方面新增:

  • rake db:forward:按单个或分组方式向前滚动执行迁移;
  • rake routes CONTROLLER=x:只查看某一个控制器的路由。

Railties 层面的弃用项

  • RAILS_ROOT 弃用,改用 Rails.root
  • RAILS_ENV 弃用,改用 Rails.env
  • RAILS_DEFAULT_LOGGER 弃用,改用 Rails.logger
  • PLUGIN/rails/tasksPLUGIN/tasks 不再被加载,所有任务必须放在 PLUGIN/lib/tasks

五、Action Pack:路由、控制器与视图的全面换代

Abstract Controller

Abstract Controller 把 Action Controller 中通用的部分抽成可复用模块:模板渲染、局部模板、助手、翻译、日志、请求-响应周期的任何环节,任何库都可以直接使用。它使 ActionMailer::Base 可以直接继承 Abstract Controller,只需把 Rails DSL 包在 Mail gem 上。需要注意:Abstract Controller 不是面向用户的 API,日常开发中基本不会直接接触它。

Action Controller

  • 生成的 application_controller.rb 默认开启 protect_from_forgery
  • cookie_verifier_secret 弃用,改由 Rails.application.config.cookie_secret 配置,并独立到 config/initializers/cookie_verification_secret.rb
  • session_store 的配置从 ActionController::Base.session 迁移到 Rails.application.config.session_store,默认值设在 config/initializers/session_store.rb
  • 新增 cookies.secure,可用 cookies.secure[:key] => value 写入加密 cookie 值;
  • 新增 cookies.permanent,可写入 cookies.permanent[:key] => value,验证失败时会抛出异常;
  • respond_to 块内的 format 调用可直接传 :notice => 'This is a flash message':alert => 'Something went wrong'flash[] 的原有用法不变;
  • 新增 respond_with 方法,简化经典的 format 块写法;
  • 新增 ActionController::Responder,让响应生成方式更灵活;
  • 弃用:filter_parameter_loggingconfig.filter_parameters << :password 取代。

Action Dispatch:重写后的路由器

Action Dispatch 是 Rails 3.0 的新组件,提供了更干净的路由实现:

  • 路由器大幅重写:Rails 路由器基于 rack_mount 并覆以 Rails DSL,成为一块可独立使用的软件。这一路线在当代仓库中被继承并演进——如今路由核心已内置在 actionpack/lib/action_dispatch/journey 中,router.rbroutes.rbparser.rb 等模块共同构成不再依赖 rack_mount 的原生实现;
  • 路由被命名空间化到应用模块内
# 旧写法(Rails 2.x):
ActionController::Routing::Routes.draw do |map|
  map.resources :posts
end

# 新写法(Rails 3):
AppName::Application.routes do
  resources :posts
end
  • 新增 match 方法,且匹配到的路由可以指向任意 Rack 应用;
  • 新增 constraints 方法,用约束守卫路由;
  • 新增 scope 方法,为不同语言或不同动作对路由命名空间化,例如:
scope 'es' do
  resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'proyecto'
end

# 得到编辑动作的 URL:/es/proyecto/1/cambiar
  • 新增 root 方法,作为 match '/', :to => path 的快捷方式;
  • match 支持可选段,如 match "/:controller(/:action(/:id))(.:format)",括号内各段均为可选;
  • 路由可以用块表达,例如 controller :home { match '/:action' }

注意:旧式 map 命令在 3.0 中仍可通过兼容层工作,但该兼容层将在 3.1 中移除。

当前仓库中,这些 DSL 方法的实现可以在 actionpack/lib/action_dispatch/routing/mapper.rb 中逐一找到:matchmapper.rb#L1848)、scopemapper.rb#L1000)、constraintsmapper.rb#L1187)与 rootmapper.rb#L1914),十余年间签名不断扩展,但骨架与 Rails 3 引入时一致。

Action Dispatch 的弃用项:

  • 面向非 REST 应用的万能路由(/:controller/:action/:id)在新生成应用中被注释掉;
  • 路由的 :path_prefix 不复存在,:name_prefix 现在会自动在值末尾追加 _

Action View

无侵入式 JavaScript(UJS)

Action View 助手经历了大重写:实现 UJS 钩子、移除旧式行内 AJAX 命令,从而允许 Rails 使用任何符合 UJS 规范的驱动。具体影响:

  • 所有 remote_<method> 助手从 Rails 核心中移除,移入 Prototype Legacy Helper gem;
  • 要让 HTML 带 UJS 钩子,改为传 :remote => true。例如:
form_for @post, :remote => true

产出:

<form action="http://host.com" id="create-post" method="post" data-remote="true">

块式助手改用 <%=

form_fordiv_for 这类从块中插入内容的助手,模板中改用 <%=

<%= form_for @post do |f| %>
  ...
<% end %>

自己写的同类助手应返回字符串,而不是手工追加输出缓冲区。而 cachecontent_for 这类行为不同的助手不受影响,仍用 <%

其他视图变化

  • 不再需要 h(string) 手动转义:所有视图模板默认开启 HTML 转义,需要原样输出时用 raw(string)
  • 助手默认输出 HTML5;
  • 表单标签助手支持单参数 I18n 取值:f.label :name 直接取 :name 的翻译;
  • I18n 的 select 标签键从 :en.support.select 调整为 :en.helpers.select
  • ERB 插值不再需要末尾减号来消除 HTML 输出中的多余换行;
  • 新增 grouped_collection_select 助手;
  • 新增 content_for?,可在渲染前检查视图内容是否已存在;
  • 表单助手传 :value => nil 会把字段 value 置为 nil,而不是回落到默认值;
  • 表单助手传 :id => nil 使字段不渲染 id 属性;
  • image_tag:alt => nil 使 img 标签不渲染 alt 属性。

六、Active Model:validates 与自定义验证器

Active Model 是 Rails 3.0 的新组件,为 ORM 提供与 Rails 交互的抽象层。校验逻辑从 Active Record 移入 Active Model,形成跨 ORM 的统一接口,核心变化是新的 validates :attribute, options_hash 快捷方法,可一次传入多种校验选项。validates 支持的选项:

选项 说明
:acceptance => Boolean 接受校验
:confirmation => Boolean 确认校验
:exclusion => { :in => Enumerable } 排除校验
:inclusion => { :in => Enumerable } 包含校验
:format => { :with => Regexp, :on => :create } 格式校验
:length => { :maximum => Fixnum } 长度校验
:numericality => Boolean 数值校验
:presence => Boolean 非空校验
:uniqueness => Boolean 唯一性校验

注意:Rails 2.3 风格的 validates_xxx_of 方法在 3.0 中全部保留,新的 validates附加便利而非替代

还可以传递可复用的验证器对象,在多个使用 Active Model 的对象间共享:

class TitleValidator < ActiveModel::EachValidator
  Titles = ['Mr.', 'Mrs.', 'Dr.']
  def validate_each(record, attribute, value)
    unless Titles.include?(value)
      record.errors[attribute] << 'must be a valid title'
    end
  end
end
class Person
  include ActiveModel::Validations
  attr_accessor :title
  validates :title, :presence => true, :title => true
end

# Active Record 中同样写法:
class Person < ActiveRecord::Base
  validates :title, :presence => true, :title => true
end

同时提供内省能力:

User.validators
User.validators_on(:login)

这套 API 在当代源码中依然原样可考:activemodel/lib/active_model/validations.rb 定义了 validates 入口,ActiveModel::EachValidator 位于 activemodel/lib/active_model/validator.rbvalidators / validators_on 内省接口亦保留至今。

七、Active Record:可链式查询接口与适配器修复

Rails 3.0 中 Active Record 得到大量关注:抽象进 Active Model、基于 Arel 全面更新查询接口、验证升级,以及大量增强与修复。所有 Rails 2.x API 通过兼容层可用,该兼容层支持到 3.1。

查询接口(Query Interface)

借助 Arel,Active Record 的核心方法现在返回 relation。2.3.x 的既有 API 在 3.1 之前不弃用、3.2 之前不移除,但新 API 提供以下可串联的方法:

方法 作用
where 设定 relation 的筛选条件
select 选择要返回的模型属性
group 按指定属性分组
having 限定分组(GROUP BY 约束)
joins 把 relation 连接到另一张表
clause 限定连接关系(JOIN 约束)
includes 预加载关联
order 按表达式排序
limit 限制返回记录数
lock 锁定返回的记录
readonly 返回只读副本
from 从多张表选择关系
scope (原 named_scope)返回 relation,可与其他 relation 方法串联
with_scope / with_exclusive_scope 现在也返回 relation,可串联
default_scope 同样与 relation 协作

在当代代码库中,这套作用域系统对应 activerecord/lib/active_record/scoping/named.rbscope/with_scope)与 activerecord/lib/active_record/scoping/default.rbdefault_scope)。

增强项

  • 新增 destroyed? 判断;
  • 关联新增 inverse_of,可直接取回已加载关联的实例而无需再查库。

补丁与弃用

修复与适配方面:SQLite 2 支持移除(转向 SQLite 3);MySQL 支持列顺序;PostgreSQL 适配器的 TIME ZONE 不再写入错误值、支持表名带多 schema、支持 XML 数据类型列;table_name 现在会缓存;Oracle 适配器经历大量 bug 修复。弃用清单:

  • named_scope 弃用,更名为 scope
  • scope 中应改用 relation 方法而非 :conditions => {} 风格查找,例如 scope :since, lambda { |time| where("created_at > ?", time) }
  • save(false) 弃用,改用 save(:validate => false)
  • Active Record 的 I18n 错误消息键从 :en.activerecord.errors.template 改为 :en.errors.template
  • model.errors.on 弃用,改用 model.errors[]
  • validates_presence_of 迁移为 validates ... :presence => true 风格;
  • ActiveRecord::Base.colorize_loggingconfig.active_record.colorize_logging 弃用,改用 Rails::LogSubscriber.colorize_loggingconfig.colorize_logging

另有一条值得留意的说明:State Machine 虽在 Active Record 主干上存在数月,但最终没有进入 Rails 3.0 发布版。

八、Active Resource:接入 Active Model

Active Resource 同样被抽取到 Active Model 体系,使其对象可与 Action Pack 无缝配合。3.0 中的变化清单相当长:

  • 通过 Active Model 获得验证能力;
  • 新增 observer 钩子;
  • 支持 HTTP 代理;
  • 支持摘要认证(digest authentication);
  • 模型命名逻辑移入 Active Model;
  • 属性改为 indifferent access 的 Hash;
  • 新增 firstlastall 作为等价 find scope 的别名;
  • find_every 在无结果时不再抛 ResourceNotFound
  • 新增 save!,对象 valid? 不成立时抛 ResourceInvalid
  • 新增 update_attributeupdate_attributes
  • 新增 exists?
  • SchemaDefinition 更名为 Schemadefine_schema 更名为 schema
  • 加载远程错误时改用 Active Resource 的 format 而非响应 content-type
  • schema 块改用 instance_eval
  • 识别 410 响应为资源已被删除;
  • 支持为连接设置 SSL 选项;
  • 设置连接超时同时影响 Net::HTTPopen_timeout

弃用项:save(false) 改为 save(:validate => false);Ruby 1.9.2 下 URI.parseURI.decode 不再使用。

九、Active Support:可摘选化(cherry pickable)

Rails 3 对 Active Support 的重点工程是“摘选化”:不再需要 require 整个库才能使用其中一块,让各核心组件跑得更轻。主要变化:

  • 大规模清理,移除全库各处不再使用的方法;
  • 不再内置 vendored 的 TZInfo、Memcache Client 与 Builder,改为依赖项,经 bundle install 安装;
  • 安全缓冲区实现于 ActiveSupport::SafeBuffer
  • 新增 Array.uniq_byArray.uniq_by!
  • 移除 Array#rand,从 Ruby 1.9 回移 Array#sample
  • 修复 TimeZone.seconds_to_utc_offset 返回值错误的 bug;
  • 新增 ActiveSupport::Notifications 中间件——如今 Rails 全框架的 instrumentation 事件总线正是这一组件;
  • ActiveSupport.use_standard_json_time_format 默认值改为 true
  • ActiveSupport.escape_html_entities_in_json 默认值改为 false
  • Integer#multiple_of? 接受 0 作为参数,接收者非 0 时返回 false;
  • string.chars 更名为 string.mb_chars
  • ActiveSupport::OrderedHash 支持 YAML 反序列化;
  • XmlMini 新增基于 LibXML/Nokogiri 的 SAX 解析器;
  • 新增 Object#presence#present? 为真返回自身,否则返回 nil);
  • 新增 String#exclude?#include? 的反义)与 Enumerable#exclude?
  • DateTime 补上 to_i,使含 DateTime 属性的模型 to_yaml 正确工作;
  • XSS 转义在 Rails 中默认开启;
  • HashWithIndifferentAccess 支持深度合并(deep-merge);
  • Enumerable#sum 兼容不响应 :size 的枚举;
  • 零长度时长的 inspect 返回 '0 seconds' 而非空串;
  • ModelName 新增 elementcollection
  • String#to_timeString#to_datetime 处理小数秒;
  • 新回调支持响应 :before / :after 的 around filter 对象;
  • ActiveSupport::OrderedHash#to_a 返回有序数组对,与 Ruby 1.9 的 Hash#to_a 对齐;
  • MissingSourceFile 常量保留但仅等于 LoadError
  • 新增 Class#class_attribute:声明可被子类继承与覆写的类级属性;
  • 移除 ActiveRecord::Associations 中的 DeprecatedCallbacks
  • Object#metaclass 更名为 Kernel#singleton_class,与 Ruby 对齐。

以下方法因 Ruby 1.8.7/1.9 已内置而移除:Integer#even? / Integer#odd?String#each_charString#start_with? / String#end_with?(第三人称别名保留)、String#bytesizeObject#tapSymbol#to_procObject#instance_variable_defined?Enumerable#none?

以下方法因框架内部不再使用而移除:Kernel#daemonizeObject#remove_subclasses_ofObject#extend_with_included_modules_fromObject#extended_byClass#remove_classRegexp#number_of_capturesRegexp.unoptionalizeRegexp.optionalize

REXML 的安全补丁保留在 Active Support 中,因为 Ruby 1.8.7 的早期补丁级仍需要它,Active Support 会自动判断是否需要应用。

十、Action Mailer:继承 Abstract Controller 的完全重写

Action Mailer 换用 Mail gem 取代 TMail,代码几乎逐行重写:它现在直接继承 Abstract Controller,把 Mail gem 包在 Rails DSL 里,代码量与重复度大幅下降。发行说明列出的行为变化:

  • 所有 mailer 默认放在 app/mailers(放在 app/models 的做法被弃用);
  • 新 API 由三个方法组成:attachmentsheadersmail
  • 原生支持内联附件,使用 attachments.inline
  • 邮件方法返回 Mail::Message 对象,对其调用 deliver 即可发送(ActionMailer.deliver(message) 被弃用,直接 message.deliver);
  • 所有投递方式抽象进 Mail gem;
  • mail 方法可接收包含全部合法邮件头字段的 hash;
  • mail 的作用类似 Action Controller 的 respond_to:可显式或隐式渲染模板,Action Mailer 会按需把邮件转成 multipart;
  • format.mime_type 块内可传 proc,显式渲染特定文本类型,或添加布局、不同模板;proc 内的 render 来自 Abstract Controller,支持相同选项;
  • 原 mailer 单元测试迁为功能测试;
  • 头部与正文的自动编码全部委托给 Mail gem,Action Mailer 会自动为邮件正文和头编码。

当前仓库中这段设计完整可考:actionmailer/lib/action_mailer/base.rb#L611mail 方法签名演化为 mail(...) 并返回 MessageDeliverydeliver/deliver_later 的执行载体),base.rb#L731base.rb#L769 仍是 headersattachments 三个核心方法之二——十余年后,"mail + headers + attachments" 的三元组依然是 Action Mailer 的形态。

Action Mailer 的弃用项:

  • :charset:content_type:mime_version:implicit_parts_order 弃用,改用 ActionMailer.default :key => value 风格的声明;
  • 动态的 create_method_name / deliver_method_name 弃用,直接调用 method_name,其返回 Mail::Message 对象;
  • ActionMailer.deliver(message) 弃用,改为 message.deliver
  • template_root 弃用,改为在 mail 块的 format.mime_type proc 中向 render 传选项;
  • body { :ivar => value } 定义实例变量的做法弃用,直接在方法内声明实例变量,视图即可使用。

十一、文档与国际化:3.0 时代的配套工作

发行说明还交代了两件配套事项。其一,国际化方面投入巨大:新版 I18n gem 带来多项速度改进;ActiveModel::TranslationActiveModel::Validations 可让任意对象获得 I18n 行为,并有 errors.messages 兜底翻译;属性可带默认翻译;表单提交标签会根据对象状态自动取 Create/Update 对应翻译;标签助手只传属性名即可走 I18n。其二,文档体系上,仓库内 API 文档随改动更新,Edge Guides 逐一同步 3.0 的变化;本仓库中这份发行说明本身即存放于 guides/source/3_0_release_notes.md,与其他各版本发行说明(2.2 至 8.2)并列,由 Mikel Lindsaar 整理成文。

结语:为什么今天仍要读这份 3.0 发行说明

把这份 2010 年的发行说明放回当前仓库对照阅读,会发现它是一份极其精确的“架构考古索引”:Application 对象与 Rails.config 演化为 railties/lib/rails 的应用初始化体系;rack_mount 路由器演化为 actionpack/lib/action_dispatch/journey 原生 Journey 引擎;validates 与自定义验证器完整保留在 activemodel/lib/active_modelmail/headers/attachments 三元组仍在 actionmailer/lib/action_mailer/base.rb 中服役;Arel 依旧以 activerecord/lib/arel 的形态支撑着可链式查询。理解 Rails 3.0 这六项架构变革与数十项 API 更迭,就是理解现代 Rails 骨架从何而来的最短路径。

登录后查看全文
热门项目推荐
相关项目推荐