1. 升级到 Rails 3.1
如果您正在升级现有应用程序,最好在升级前进行良好的测试覆盖。您还应该首先升级到 Rails 3(如果尚未升级),并确保您的应用程序在尝试更新到 Rails 3.1 之前仍能按预期运行。然后请注意以下更改:
1.1. Rails 3.1 需要至少 Ruby 1.8.7
Rails 3.1 需要 Ruby 1.8.7 或更高版本。对所有以前 Ruby 版本的支持已正式终止,您应该尽快升级。Rails 3.1 也兼容 Ruby 1.9.2。
请注意,Ruby 1.8.7 p248 和 p249 存在导致 Rails 崩溃的封送处理错误。Ruby Enterprise Edition 已在 1.8.7-2010.02 版本之后修复了这些问题。在 1.9 方面,Ruby 1.9.1 不可用,因为它会直接导致段错误,因此如果您想使用 1.9.x,请直接跳到 1.9.2 以便顺利运行。
1.2. 应用程序中需要更新的内容
以下更改旨在将您的应用程序升级到 Rails 3.1.3,即 Rails 的最新 3.1.x 版本。
1.2.1. Gemfile
对您的 Gemfile 进行以下更改。
gem "rails", "= 3.1.3"
gem "mysql2"
# Needed for the new asset pipeline
group :assets do
gem "sass-rails", "~> 3.1.5"
gem "coffee-rails", "~> 3.1.1"
gem "uglifier", ">= 1.0.3"
end
# jQuery is the default JavaScript library in Rails 3.1
gem "jquery-rails"
1.2.2. config/application.rb
资产管道需要以下附加项
config.assets.enabled = true config.assets.version = '1.0'如果您的应用程序将“/assets”路由用于某个资源,您可能需要更改用于资产的前缀以避免冲突
# Defaults to '/assets' config.assets.prefix = '/asset-files'
1.2.3. config/environments/development.rb
移除 RJS 设置
config.action_view.debug_rjs = true。如果启用资产管道,请添加以下内容。
# Do not compress assets config.assets.compress = false # Expands the lines which load the assets config.assets.debug = true
1.2.4. config/environments/production.rb
同样,以下大部分更改都适用于资产管道。您可以在资产管道指南中阅读更多相关信息。
# Compress JavaScripts and CSS config.assets.compress = true # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false # Generate digests for assets URLs config.assets.digest = true # Defaults to Rails.root.join("public/assets") # config.assets.manifest = YOUR_PATH # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) # config.assets.precompile `= %w( admin.js admin.css ) # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true
1.2.5. config/environments/test.rb
# Configure static asset server for tests with Cache-Control for performance
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
1.2.6. config/initializers/wrap_parameters.rb
如果您希望将参数包装到嵌套哈希中,请添加此文件并包含以下内容。这在新应用程序中默认启用。
# Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do wrap_parameters :format => [:json] end # Disable root element in JSON by default. ActiveSupport.on_load(:active_record) do self.include_root_in_json = false end
1.2.7. 移除视图中资产助手引用中的 :cache 和 :concat 选项
- 使用资产管道后,不再使用 :cache 和 :concat 选项,请从您的视图中删除这些选项。
2. 创建 Rails 3.1 应用程序
# You should have the 'rails' RubyGem installed
$ rails new myapp
$ cd myapp
2.1. 嵌入 Gem
Rails 现在在应用程序根目录中使用 Gemfile 来确定您的应用程序启动所需的 gem。此 Gemfile 由 Bundler gem 处理,然后安装所有依赖项。它甚至可以将所有依赖项本地安装到您的应用程序中,以便它不依赖于系统 gem。
更多信息: - bundler 主页
2.2. 前沿开发
Bundler 和 Gemfile 使冻结您的 Rails 应用程序变得轻而易举,使用新的专用 bundle 命令。如果您想直接从 Git 仓库捆绑,可以传递 --edge 标志
$ rails new myapp --edge
如果您本地签出了 Rails 仓库并希望使用它生成应用程序,您可以传递 --dev 标志
$ ruby /path/to/rails/railties/bin/rails new myapp --dev
3. Rails 架构变更
3.1. 资产管道
Rails 3.1 的主要变化是资产管道。它使 CSS 和 JavaScript 成为一流的代码公民,并实现了适当的组织,包括在插件和引擎中的使用。
资产管道由 Sprockets 提供支持,并在资产管道指南中进行了介绍。
3.2. HTTP 流式传输
HTTP 流式传输是 Rails 3.1 中的另一项新更改。它允许浏览器在服务器仍在生成响应时下载您的样式表和 JavaScript 文件。这需要 Ruby 1.9.2,是可选的,也需要 Web 服务器的支持,但 NGINX 和 Unicorn 的流行组合已准备好利用它。
3.3. 默认 JS 库现在是 jQuery
jQuery 是 Rails 3.1 附带的默认 JavaScript 库。但是,如果您使用 Prototype,切换起来也很简单。
$ rails new myapp -j prototype
3.4. 身份映射
Active Record 在 Rails 3.1 中有一个身份映射。身份映射保存以前实例化的记录,并在再次访问时返回与该记录关联的对象。身份映射是按请求创建的,并在请求完成时刷新。
Rails 3.1 默认关闭身份映射。
4. Railties
jQuery 是新的默认 JavaScript 库。
jQuery 和 Prototype 不再嵌入,从现在起由
jquery-rails和prototype-railsgem 提供。应用程序生成器接受一个选项
-j,它可以是任意字符串。如果传递“foo”,则 gem “foo-rails”会添加到Gemfile中,并且应用程序 JavaScript 清单需要“foo”和“foo_ujs”。目前只有“prototype-rails”和“jquery-rails”存在,并通过资产管道提供这些文件。除非指定
--skip-gemfile或--skip-bundle,否则生成应用程序或插件会运行bundle install。控制器和资源生成器现在将自动生成资产存根(这可以通过
--skip-assets关闭)。如果 CoffeeScript 和 Sass 可用,这些存根将使用它们。Scaffold 和 app 生成器在 Ruby 1.9 上运行时使用 Ruby 1.9 风格的哈希。要生成旧风格的哈希,可以传递
--old-style-hash。Scaffold 控制器生成器为 JSON 而不是 XML 创建格式块。
Active Record 日志记录被定向到 STDOUT 并在控制台中内联显示。
添加了
config.force_ssl配置,它加载Rack::SSL中间件并强制所有请求都使用 HTTPS 协议。添加了
rails plugin new命令,它生成一个带有 gemspec、测试和用于测试的虚拟应用程序的 Rails 插件。将
Rack::Etag和Rack::ConditionalGet添加到默认中间件栈。将
Rack::Cache添加到默认中间件栈。引擎进行了重大更新 - 您可以在任何路径挂载它们,启用资产,运行生成器等。
5. Action Pack
5.1. Action Controller
如果 CSRF 令牌真实性无法验证,则会发出警告。
在控制器中指定
force_ssl以强制浏览器在该特定控制器上通过 HTTPS 协议传输数据。要限制特定操作,可以使用:only或:except。config.filter_parameters中指定的敏感查询字符串参数现在将从日志中的请求路径中过滤掉。对
to_param返回nil的 URL 参数现在从查询字符串中移除。添加了
ActionController::ParamsWrapper,用于将参数包装到嵌套哈希中,并在新应用程序中默认对 JSON 请求启用。这可以在config/initializers/wrap_parameters.rb中自定义。添加了
config.action_controller.include_all_helpers。默认情况下,ActionController::Base中会执行helper :all,它默认包含所有助手。将include_all_helpers设置为false将导致仅包含 application_helper 和与控制器对应的助手(例如 foo_controller 的 foo_helper)。url_for和命名 URL 助手现在接受:subdomain和:domain作为选项。添加了
Base.http_basic_authenticate_with,通过单个类方法调用执行简单的 HTTP 基本认证。class PostsController < ApplicationController USER_NAME, PASSWORD = "dhh", "secret" before_filter :authenticate, :except => [ :index ] def index render :text => "Everyone can see me!" end def edit render :text => "I'm only accessible if you know the password" end private def authenticate authenticate_or_request_with_http_basic do |user_name, password| user_name == USER_NAME && password == PASSWORD end end end..现在可以写成
class PostsController < ApplicationController http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index def index render :text => "Everyone can see me!" end def edit render :text => "I'm only accessible if you know the password" end end添加了流式传输支持,您可以通过以下方式启用它
class PostsController < ActionController::Base stream end您可以使用
:only或:except将其限制为某些操作。有关更多信息,请阅读ActionController::Streaming处的文档。redirect 路由方法现在还接受一个选项哈希,该哈希将仅更改 URL 中的相关部分,或者接受一个响应 call 的对象,从而允许重定向被重用。
5.2. Action Dispatch
config.action_dispatch.x_sendfile_header现在默认为nil,并且config/environments/production.rb没有为其设置任何特定值。这允许服务器通过X-Sendfile-Type进行设置。ActionDispatch::MiddlewareStack现在使用组合而不是继承,并且不再是数组。添加了
ActionDispatch::Request.ignore_accept_header以忽略 accept 头。将
Rack::Cache添加到默认栈。将 etag 责任从
ActionDispatch::Response移到中间件栈。依赖
Rack::Session存储 API 以在 Ruby 世界中实现更大的兼容性。这与以前不兼容,因为Rack::Session期望#get_session接受四个参数,并且需要#destroy_session而不是简单的#destroy。模板查找现在会向上搜索继承链。
5.3. Action View
为
form_tag添加了:authenticity_token选项,用于自定义处理或通过传递:authenticity_token => false来省略令牌。创建了
ActionView::Renderer并为ActionView::Context指定了 API。Rails 3.1 禁止原地
SafeBuffer变异。添加了 HTML5
button_tag助手。file_field自动将:multipart => true添加到包含的表单。添加了一个方便的习语,用于从选项的
:data哈希中在标签助手中生成 HTML5 data-* 属性tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)}) # => <div data-name="Stephen" data-city-state="["Chicago","IL"]" />
键是短横线连接的。值是 JSON 编码的,字符串和符号除外。
csrf_meta_tag重命名为csrf_meta_tags,并别名为csrf_meta_tag以实现向后兼容。旧的模板处理程序 API 已弃用,新的 API 仅要求模板处理程序响应 call。
rhtml 和 rxml 最终作为模板处理程序被移除。
config.action_view.cache_template_loading已恢复,允许决定是否缓存模板。提交表单助手不再生成 ID“object_name_id”。
允许
FormHelper#form_for将:method指定为直接选项,而不是通过:html哈希。form_for(@post, remote: true, method: :delete)代替form_for(@post, remote: true, html: { method: :delete })。提供了
JavaScriptHelper#j()作为JavaScriptHelper#escape_javascript()的别名。这取代了 JSON gem 在使用 JavaScriptHelper 的模板中添加的Object#j()方法。允许 datetime 选择器中使用 AM/PM 格式。
auto_link已从 Rails 中移除,并提取到 rails_autolink gem 中
6. Active Record
添加了一个类方法
pluralize_table_names,用于对单个模型的表名进行单数/复数化。以前这只能通过ActiveRecord::Base.pluralize_table_names全局设置为所有模型。class User < ActiveRecord::Base self.pluralize_table_names = false end为单数关联添加了属性的块设置。该块将在实例初始化后被调用。
class User < ActiveRecord::Base has_one :account end user.build_account{ |a| a.credit_limit = 100.0 }添加了
ActiveRecord::Base.attribute_names以返回属性名称列表。如果模型是抽象的或表不存在,这将返回一个空数组。CSV Fixtures 已弃用,并将在 Rails 3.2.0 中移除支持。
ActiveRecord#new、ActiveRecord#create和ActiveRecord#update_attributes都接受第二个哈希作为选项,允许您在分配属性时指定要考虑的角色。这是在 Active Model 新的大量赋值功能之上构建的class Post < ActiveRecord::Base attr_accessible :title attr_accessible :title, :published_at, :as => :admin end Post.new(params[:post], :as => :admin)default_scope现在可以接受一个块、lambda 或任何其他响应 call 的对象,用于惰性求值。默认作用域现在在可能的最晚时间进行评估,以避免作用域隐式包含默认作用域的问题,然后通过 Model.unscoped 无法摆脱默认作用域。
PostgreSQL 适配器仅支持 PostgreSQL 8.2 及更高版本。
ConnectionManagement中间件已更改,以便在 rack 主体刷新后清理连接池。在 Active Record 上添加了一个
update_column方法。这个新方法更新对象的给定属性,跳过验证和回调。除非您确定不想执行任何回调,包括updated_at列的修改,否则建议使用update_attributes或update_attribute。它不应该在新记录上调用。具有
:through选项的关联现在可以使用任何关联作为 through 或 source 关联,包括其他具有:through选项的关联和has_and_belongs_to_many关联。当前数据库连接的配置现在可以通过
ActiveRecord::Base.connection_config访问。除非同时提供 limits 和 offsets,否则将从 COUNT 查询中移除它们。
People.limit(1).count # => 'SELECT COUNT(*) FROM people' People.offset(1).count # => 'SELECT COUNT(*) FROM people' People.limit(1).offset(1).count # => 'SELECT COUNT(*) FROM people LIMIT 1 OFFSET 1'ActiveRecord::Associations::AssociationProxy已拆分。现在有一个Association类(及其子类)负责操作关联,然后有一个单独的、薄薄的包装器CollectionProxy,它代理集合关联。这可以防止命名空间污染,分离关注点,并允许进一步的重构。单数关联(
has_one,belongs_to)不再具有代理,只返回关联记录或nil。这意味着您不应使用未文档化的方法,例如bob.mother.create- 请改用bob.create_mother。支持
has_many :through关联上的:dependent选项。出于历史和实际原因,association.delete(*records)默认采用:delete_all删除策略,尽管常规 has_many 的默认策略是:nullify。此外,这仅在源反射是 belongs_to 时才有效。对于其他情况,您应该直接修改 through 关联。has_and_belongs_to_many和has_many :through的association.destroy行为已更改。从现在开始,关联上的“destroy”或“delete”将表示“移除链接”,而不是(不一定)“移除关联记录”。以前,
has_and_belongs_to_many.destroy(*records)会销毁记录本身。它不会删除联接表中的任何记录。现在,它会删除联接表中的记录。以前,
has_many_through.destroy(*records)会销毁记录本身以及联接表中的记录。[注意:情况并非总是如此;Rails 早期版本只删除记录本身。]现在,它只销毁联接表中的记录。请注意,此更改在一定程度上与以前不兼容,但遗憾的是,在更改之前无法“弃用”它。进行此更改是为了在不同类型的关联之间保持“destroy”或“delete”含义的一致性。如果您希望销毁记录本身,可以执行
records.association.each(&:destroy)。向
change_table添加:bulk => true选项,以使用单个 ALTER 语句完成块中定义的所有模式更改。change_table(:users, :bulk => true) do |t| t.string :company_name t.change :birthdate, :datetime end移除了对访问
has_and_belongs_to_many联接表上的属性的支持。需要使用has_many :through。为
has_one和belongs_to关联添加了create_association!方法。迁移现在是可逆的,这意味着 Rails 将找出如何反转您的迁移。要使用可逆迁移,只需定义
change方法。class MyMigration < ActiveRecord::Migration def change create_table(:horses) do |t| t.column :content, :text t.column :remind_at, :datetime end end end有些事情无法为您自动反转。如果您知道如何反转这些事情,您应该在迁移中定义
up和down。如果您在 change 中定义了无法反转的内容,则在向下回滚时将引发IrreversibleMigration异常。迁移现在使用实例方法而不是类方法
class FooMigration < ActiveRecord::Migration def up # Not self.up # ... end end由模型和构造性迁移生成器(例如,add_name_to_users)生成的迁移文件使用可逆迁移的
change方法,而不是普通的up和down方法。移除了对关联上内插字符串 SQL 条件的支持。相反,应该使用 proc。
has_many :things, :conditions => 'foo = #{bar}' # before has_many :things, :conditions => proc { "foo = #{bar}" } # after在 proc 内部,
self是关联的所有者对象,除非您正在预加载关联,在这种情况下self是关联所在的类。您可以在 proc 内部包含任何“正常”条件,因此以下内容也适用
has_many :things, :conditions => proc { ["foo = ?", bar] }以前
has_and_belongs_to_many关联上的:insert_sql和:delete_sql允许您调用“record”以获取正在插入或删除的记录。这现在作为参数传递给 proc。添加了
ActiveRecord::Base#has_secure_password(通过ActiveModel::SecurePassword)以封装使用 BCrypt 加密和加盐的简单密码用法。# Schema: User(name:string, password_digest:string, password_salt:string) class User < ActiveRecord::Base has_secure_password end当生成模型时,默认情况下会为
belongs_to或references列添加add_index。设置
belongs_to对象的 ID 将更新对该对象的引用。ActiveRecord::Base#dup和ActiveRecord::Base#clone的语义已更改,以更接近于正常的 Ruby dup 和 clone 语义。调用
ActiveRecord::Base#clone将导致记录的浅拷贝,包括复制冻结状态。不会调用任何回调。调用
ActiveRecord::Base#dup将复制记录,包括调用初始化后钩子。冻结状态不会被复制,所有关联都将被清除。复制的记录将对new_record?返回true,id 字段为nil,并且可以保存。查询缓存现在与预处理语句一起使用。应用程序中无需进行任何更改。
7. Active Model
attr_accessible接受一个选项:as以指定角色。InclusionValidator、ExclusionValidator和FormatValidator现在接受一个可以是 proc、lambda 或任何响应call的对象作为选项。此选项将以当前记录作为参数调用,并返回一个响应include?的对象(用于InclusionValidator和ExclusionValidator),以及返回一个正则表达式对象(用于FormatValidator)。添加了
ActiveModel::SecurePassword,用于封装使用 BCrypt 加密和加盐的简单密码用法。ActiveModel::AttributeMethods允许按需定义属性。增加了对选择性启用和禁用观察者的支持。
不再支持备用
I18n命名空间查找。
8. Active Resource
所有请求的默认格式已更改为 JSON。如果您想继续使用 XML,您需要在类中设置
self.format = :xml。例如,class User < ActiveResource::Base self.format = :xml end
9. Active Support
ActiveSupport::Dependencies现在在load_missing_constant中找到现有常量时会引发NameError。添加了一个新的报告方法
Kernel#quietly,它可以同时静默STDOUT和STDERR。添加了
String#inquiry作为将字符串转换为StringInquirer对象的便捷方法。添加了
Object#in?以测试一个对象是否包含在另一个对象中。LocalCache策略现在是一个真正的中间件类,不再是匿名类。已引入
ActiveSupport::Dependencies::ClassCache类,用于保存对可重载类的引用。ActiveSupport::Dependencies::Reference已重构,以直接利用新的ClassCache。在 Ruby 1.8 中,
Range#cover?作为Range#include?的别名被反向移植。为 Date/DateTime/Time 添加了
weeks_ago和prev_week。为
ActiveSupport::Dependencies.remove_unloadable_constants!添加了before_remove_const回调。
弃用
ActiveSupport::SecureRandom已弃用,转而使用 Ruby 标准库中的SecureRandom。
10. 致谢
请参阅Rails 贡献者完整列表,感谢许多人花费大量时间使 Rails 成为一个稳定而健壮的框架。向他们所有人致敬。
Rails 3.1 发布说明由 Vijay Dev 整理