经过2个星期的折腾,终于将一个项目从rails2.3+ruby1.8升级到rails3.2+ruby1.9,记录一下过程和踩到的地雷:
升级流程:
1. 在ruby1.8和rails2.3的环境下,在项目下安装rails_upgrade插件: https://github.com/rails/rails_upgrade 运行下列命令,将输出的内容保存供后续使用。
A. rake rails:upgrade:check, 它会查找不兼容的语法和插件
B. rake rails:upgrade:routes, 会把rails2.3格式的route文件转化成rails3格式
C. rake rails:upgrade:gems, 会把写在environment.rb里面的gem管理方式变成bundle管理的
Gemfile格式
D. rake rails:upgrade:configuration, 会将原先在environment.rb里面的其他设置转化成rails3格式的config/application.rb文件
2. 用rvm切换到ruby 1.9.3, gem install rails v=3.2
A. 执行rails new old_app_path 会提醒你是否要覆盖一些文件(比如routes.rb等),可以选择全部覆盖(做好备份)
B. 将1.B生成的内容,覆盖到routes.rb
C. 将1.C生成的内容,覆盖到Gemfile
D. 将1.D生成的内容,覆盖到application.rb
E. 执行bundle install,安装必要的gem
3. 根据1.A的结果,升级插件和改必要的语法,如下几个基本上都是可以
全局查找替换的:
A. 插件升级,rails2的大部分插件到了3以后基本上就不能用了,比如searchlogic,可用meta_search来替代,比如cache-money,可用record-cache替代
B. 支持block的helper改变,比如form_for等支持block的helper,现在必须多个等号,改成‘<%= form_for’才能输出html
C. RAILS_ROOT, RAILS_ENV等常量写法,被Rails.root, Rails.env等模块方法取代 ( http://quaran.to/blog/2010/02/03/the-rails-module/ )
D. named_scope 改成了 scope ( https://github.com/rails/rails/commit/d60bb0a9e4be2ac0a9de9a69041a4ddc2e0cc914 )
E. 邮件发送api改变 ( http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3 )
4. 下面是几个比较折腾和change log里面不太注意的地方:
A. Rails 3默认使用了safebuffers: http://yehudakatz.com/2010/02/01/safebuffers-and-rails-3-0/这样就可以不需要到处加<%= h ... %>,非常安全也非常方便,但是rails 2的项目中很多view和helper都需要改写,一些不需要escape的代码还要特别注意加上html_safe (比如richeditor的输出结果)
B. ActiveRecord callback的语法改变,rails2我们可以在model里面写
class User
def after_save
self.xxx
end
end
现在必须改成block方式:
class User
before_save do |user|
user.xxx
end
end
C. rails_upgrade插件自动生成的routes.rb大部分能够自动工作,但是还是有
发现一些namespace的route,自动生成的会出错,需要手工处理一下,改写一下。
D. class_inheritable_accessor 方法改成了 class_attribute
E. request.request_uri 方法改成了 request.fullpath
F. rails3推荐无侵入式的
JS,一些旧的onclick的helper都改写成ujs方式
G. yaml的array格式改变(这个好像是ruby1.9的改变),原先可以写
day_names: [星期一,星期二...]
现在改成了
day_names
- 星期一
- 星期二
H. ruby 1.9要求每个含有utf8字符的rb文件,必须在文件第一行有magic comment: # -*- encoding : utf-8 -*- 我觉的这个很折腾,为什么不是默认unicode呢?
5. 4里面的麻烦还算好,基本上
耐心改写,测试都可以搞定,这个项目升级遇到最大的麻烦是ruby 1.9 String encoding + yaml
序列化的改变,1.8的String对象是不带encoding属性的,serialize一个属性,如果有中文的话,会当作binary存入数据库。
class Product
serialize :properties, Hash
end
升级以后,必须用db migration,将数据库里面所有的数据进行force_encoding,然后再保存:
def up
rename_column :products, :properties, :old_properties
add_column :products, :properties, :text
Product.reset_column_information
Product.find(:all).each{|p|
if pro = p.old_properties
pro.each {|k, v|
pro[k] = v.force_encoding('UTF-8') if v.is_a? String
}
p.properties = pro
p.save!
end
}
end