升级到 Rails 4,你的应用需要准备什么?

一个新的 Rails 版本即将发布了,随之带来了很多的修改、依赖和新特性。

让我们看一下,要使用 Rails 4,你需要为你的应用准备些什么。

升级的方式

要为 Rails 4 做好准备最简单的方法就是让你的应用运行在 Rails 3.2 上。如果你目前还不是使用 Rails 3.2,建议使用小版本方式升级,就是说从 3.0 升级到 3.1 ,然后再从 3.1 升级到 3.2

废弃 Deprecations

一些方法将在 Rails 4 中被完全删除,我们应该知道这些,并事先做好准备。

Rails 4 只支持 Ruby 1.9.3+

Rails 4 将只支持 Ruby 1.9.3 或者更新的版本,因此必须确保你的应用可在 Ruby 1.9.3 版本上运行。

如果你使用的是 Ruby 1.9.x,这样升级会更加直接。

如果你还在使用 Ruby 1.8.7,那需要做多点工作。

现在大多数 gems 都可以运行在 Ruby 1.9 版本,或者也有了替代品。例如 rvmrbenv 这样的工具可以帮助我们的应用程序运行在多个 Ruby 的版本。

在你的 Gemfil 中使用条件语句可以方便的处理不同环境下的不同 gems,直到你完全移植到 Ruby 1.9.x 上。

例如:

gem 'ruby18-only-gem', :platforms => :ruby_18
gem 'ruby19-only-gem', :platforms => :ruby_19
#More on this can be seen in the Bundler manpages:
#http://gembundler.com/man/gemfile.5.html#PLATFORMS-platforms-

关于 1.8 和 1.9 之间的改变可看 Peter Cooper 写的这篇文章 the Ruby 1.9 walkthrough . 强烈推荐!

不再有 vendor/plugins

Rails 4 将删除 Rails::Plugins 类,所以将不会再加载 vender/plugins 目录下的任何代码。

大多数应用应该依赖于 gems 而不是插件。但如果你在 vender/plugins 中还有一些代码,你有两种选择:

这里是关于废弃插件的说明 commit

路由匹配

关于路由,匹配方法不再作为是 catch-all 选项,你可以指定需要响应什么 HTTP 方法,包括 GET/POST 之类的。

#Rails 3.2
match "/users/:id" => "users#show"
#Rails 4.0
match "/users/:id" => "users#show", via: :get
#or specify multiple verbs
match "/users" => "users#index", via: [:get, :post]

另外一个更好兼容 Rails 3.2 的方法是显式的指定 HTTP 方法,是 GET 或者 POST,或者是其他的方法。这样你就可以兼容现在的版本和 Rails 4.0.

#Rails 3.2 and 4.0 compatible
get "/users/:id" => "users#show"
# multiple verbs
get "/users" => "users#index"
post "/users" => "users#index"

ActiveRecord

ActiveRecord 范围需要一个 Callable 对象。

在 Rails 4 中,所有 ActiveRecord 范围必须使用一个 callable 对象来定义:

#Rails 3.2
scope :recent, where(created_at: Time.now - 2.weeks)
#Rails 4
scope :recent, -> { where("created_at > ?", Time.now - 2.weeks).order("created_at desc") }
scope :active, -> { where(status: 'active') }

这个可避免一些关于日期和时间对象的微小 bug,无需动态的评估。

被移除的代码

在 Rails 4 中有很多代码会被删除,别担心,因为大多数被删除的代码还会作为独立的 gems 存在,这样有助于更平滑的迁移。

被删除的代码包括:


特别值得一提的注意事项:

Activerecord-deprecated-finders 是 Rails 4.0 中默认提供废弃功能的依赖包,但它也将在 4.1 版本中被删除。因此你需要密切关注所有的警告信息,并开始修复这些警告。

Rails 指南 提供一个很有用的解释,关于在大多数情况下如何修改动态查找器:

所有动态的方法除了 findby… 和 findby…! 外都已废弃,你可以使用如下的替代方法:

所有的那些 gems 都可以帮你实现平滑的迁移。我的建议是:对一个完全的 Rails 4 环境,通过警告信息来帮你的代码适应于最新版本的语法。

新特性

现在该是介绍最有趣的部分了!

Rails 4 增加了大量的新特性,好消息是这些新特性都可以在 Rails 3.2 中通过 gems 方式获取。同时 Rails 4 也提供了预览版不可方便进行升级测试。

下面我们来看看这些新特性。

强参数 (gem)

在围绕着 mass-assignment保护 产生了不少争议之后,我们对各种不同的方法进行
探讨。

Rails 3.2 的做法是在模型中使用 attr_accessible 和 attr_protected 方法。

Rails 4 则需要从完全不同的角度来看,为模型分配参数的工作将由控制器负责。

#Rails 3.2
class User < ActiveRecord::Base
  attr_protected :name, :email
end
class UsersController < ApplicationController
  def create
    @user = User.new params[:user]
    if @user.save
      redirect_to @user
    else
      render :new
    end
  end
end
#Rails 4.0
class User < ActiveRecord::Base
  include ActiveModel::ForbiddenAttributesProtection
end
class UsersController < ApplicationController
  def create
    @user = User.new params.require(:user).permit(:name, :email)
    if @user.save
      redirect_to @user
    else
      render :new
    end
  end
end

也可以简化成类似的

#Rails 4
class UsersController < ApplicationController
  def create
    @user = User.new user_params
    #  ...
  end
  private
  def user_params
    params.require(:user).permit(:name, :email)
  end
end

这种方法的好处是,我们可以在一个面向用户的方法里面过滤不同的参数,而不是在一个拥有管理权限的地方过滤。

还有一个好处,不同的方法可以允许不同组的属性。让控制器来控制模型应该接受什么是明智的选择。

在使用这个gem的时候还要记住一点,你需要添加一行代码到 config/application.rb:

config.active_record.whitelist_attributes = false
这个  gem  还提供了一个清晰的 README,非常值得一读。Railser的福气啊,想知道更多的话还有一个  Railscast 视频介绍。

Cache 摘要和和 Russian Doll Caching (gem)

在 Rails 4 中 action 和页面缓存被移除了,同时也引入了一种新的方式来存储缓存,那就是 基于键的失效期.

主思路就是增加 updated\_at 属性到缓存键,当记录更改时,缓存键也跟着更改,这样就可以获取新的数据。

这个方法导致了大量的缓存垃圾,因此更适合使用类似 memcached 同类的存储,因为当空间用完时会自动清除最老的数据。

同时,对于视图而言,它生成文件的 MD5 checksum 并存做缓存的键,如果文件做任何改动,缓存的键也跟着更改,这样就可以重新加载文件内容。

#Rails 3.2
<% cache ['v1', @user] do %>
...
<% end %>
#Rails 4.0
<% cache @user do %>
...
<% end %>
#this will generate a key like
# views/users/1-201222172130/1a79a4d60de6718e8e5b326e338ae533

在嵌套视图中也可以使用,它能识别是嵌套视图的情况。这里有一个相关的 Railscast

声明式 ETags (gem)

在 Rails 4 中你将可以设置控制器范围的 ETag 后缀。当一个 action 依赖于多个记录或者是登录用户时很有用。

这真的是一个非常简单的方法用以获取更好的HTTP缓存。

一个简单的例子:

class TodosController < ApplicationController
  etag { current_user.try :id }
  etag { @todo_list }
  before_fiter :find_todo_list
  def show
    @todo = @todo_list.todos.find(params[:id])
    fresh_when(@todo)
  end
  private
  def find_todo_list
    @todo_list = TodoList.find(params[:todo_list_id])
  end
end

在这个例子中,第一个 etag 块检查当前用户,确保不会出现两个不同的用户使用相同的缓存 ETag。第二个使用 TotoList 对象作为 ETag 的一部分,因此修改了 todo list 就会同时修改 ETag。

Turbolinks (gem)

Turbolinks 类似 pjax 的兄弟,它使用 pushState,触发一个 XHR 请求,然后替换 <body> 内容。有三个优点:


Rails 4 默认启用 Turbolinks。但如果你使用太多 dom ready 事件的话可能会带来一些问题。TurboLinks 声明了 4 个新的事件:


你必须检查你的 JavaScript 代码,并在需要的时候修复它。

想现在使用,只需安装那个 gem 然后在你的主 JavaScript 文件(通常是 application.js)中添加 //= require turbolinks

关于这个特性,这里有一篇很好的 Railscast

Concerns

Rails 4 引入了新的默认模式用于避免代码重复。

Routing Concerns (gem)

当多个resources或methods被几个routes共享时, 会产生大量重复代码. 这个功能在routes上给了我们一个新的concern定义, 来提高可读性以及使代码更DRY.

#Rails 3.2
resources :messages  do
  resources :comments
  post :trash, :restore, on: :member
end
resources :documents do
  resources :comments
  post :trash, :restore, on: :member
end
#Rails 4
concern :commentable do
  resources :comments
end
concern :trashable do
  post :trash, :restore, on: :member
end
resources :messages, :documents, concerns: [:commentable, :trashable]

这功能可以在Rails 3.2中通过加装routing_concerns gem来使用.

Models 和 Controller 关注

Rails 4 默认增加两个新的文件夹:path:app/controllers/concerns 和 app/models/concerns .

DHH 上有篇 文章 解释了这个思路。

一般代码是存在于 lib 目录,这些新的目录让事情看起来更加简洁和容易查找。

要完成这点修改,你仅需简单的把下面这行代码添加到 yourconfig/application.rb

config.autoload_paths += Dir["#{config.root}/app/controllers/concerns", "#{config.root}/app/models/concerns"]

然后再把你的 model 和 controller 等这些模块移到这些目录中。

Dalli 成为了 memcache 客户端(gem)

Dalli 将替换掉掉 memcache-client 而成为 gem 的默认缓存客户端。

这将带来以下几点改进:


现在要在你的应用中测试这项改动,你仅需简单地做以下两点:

在你的 Gemfile 里:

gem 'dalli'

Inconfig/environments/production.rb(或者是你使用的memcached环境):

config.cache_store = :dalli_store
# just be sure to change this back to :mem_cache_store when upgrading to Rails 4

要注意一件事:Dalli 依赖于 memcached 1.4+,因此如果你使用了旧的 memcached 版本,那么你也要先升级你的 memcached!

默认启用线程安全

在新的 Rails 应用中,产品模式下默认启用线程安全选项,你可设置 config.cache_classes 和 config.eager_loader 值为 false 来关闭它。

这里应该不会有太多问题,除非应用过分的依赖于线程安全。

这里有一篇 Aaron Patterson 写的博客解释了这个改变:config.threadsafe!: What does it do?

你现在就可以在应用中启用 threadsafe! 选项来查看具体表现。当升级到 Rails 4 后你就会看到一个警告,你可以移除这个配置行。

总结

本文把即将发布的 Rails 4 的主要更新内容都包含了。在这些更新中,大多数应用都能够轻易地升级到 Rails 4。但不管怎么说,Rails 4 还在积极的开发中,因此,将来还会有一些其他的更新。我将会持续关注并不断更新本文。

进一步阅读: