分享 Rails 2 升级到 Rails 3 的一些经验

microad_liy · 2013年08月20日 · 最后由 microad_liy 回复于 2013年08月22日 · 8281 次阅读

■作业要求 Ruby 1.8.7 -> Ruby 1.9.3 Rails 2.3.16 -> Rails 3.2.13 ■服务器环境 mysql5.5

■升级过程 1.请理解以下内容 Rails3 Beta 版重点导览 (http://ihower.tw/blog/archives/3653) Rails3 RC 版重点导览 (http://ihower.tw/blog/archives/4590) Rails 3.1 RC 版重点导览 (http://ihower.tw/blog/archives/5611) 环境设定与 Bundler(http://ihower.tw/rails3/environments-and-bundler.html) Routing 路由 (http://ihower.tw/rails3/routing.html) Assets 与 Ajax(http://ihower.tw/rails3/assets-and-ajax.html)

2.安装 ruby1.9、rails3 环境,新建 rails3 工程,将 rails2 代码放到 rails3 工程中。 这一步主要保证 rails2 代码放到 rails3 环境中可以正常启动,怎样能正常启动呢? ①确保 rails 本身框架级代码修改正确 (新增 config/application.rb、变更 config/routes.rb 等) 使用 rails_upgrade 升级插件 (https://github.com/rails/rails_upgrade) 可以比较轻松完成这一步. rails_upgrade 命令: rake rails:upgrade:check 命令会找出 rails2->rails3.0 所有需要升级的代码及修改方法 rake rails:upgrade:routes 命令会产生 rails3 用 route 文件 (config/routes.rb) rake rails:upgrade:configuration 命令产生 rails3 用 config 文件 (config/application.rb) rake rails:upgrade:gems 命令产生 rails3 用 gem 管理文件 (Gemfile)

rails_upgrade 运行结果例

# rake rails:upgrade:check


/////rake rails:upgrade:check结果开始/////
Old router API
The router API has totally changed.
More information: http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/

The culprits:
        - config/routes.rb

New file needed: config/application.rb
You need to add a config/application.rb.
More information: http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade

The culprits:
        - config/application.rb


named_scope is now just scope
The named_scope method has been renamed to just scope.
More information: http://github.com/rails/rails/commit/d60bb0a9e4be2ac0a9de9a69041a4ddc2e0cc914

The culprits:
        - app/models/xxx1.rb
        - app/models/xxx2.rb

... ...

/////rake rails:upgrade:check结果结束/////



# rake rails:upgrade:routes

/////rake rails:upgrade:routes结果开始/////

xxx::Application.routes.draw do
  match '' => 'default#index'
  match 'xxx1' => 'default#login', :id => 'xxx1'
  match 'xxx2' => 'default#login', :id => 'xxx2'
  match '/:controller(/:action(/:id))'
  match ':controller/:action/:id/:id2' => '#index'
  match ':controller/:action/:id/:id2/:id3' => '#index'
end
/////rake rails:upgrade:routes结果结束/////



# rake rails:upgrade:configuration
/////rake rails:upgrade:configuration结果开始/////
# Put this in config/application.rb
require File.expand_path('../boot', __FILE__)

require 'rails/all'

Bundler.require(:default, Rails.env) if defined?(Bundler)

module Xxxx
  class Application < Rails::Application
    config.autoload_paths += [config.root.join('lib')]
    config.encoding = 'utf-8'
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Add additional load paths for your own custom dirs
    # config.load_paths += %W( #{RAILS_ROOT}/extras )

    # Specify gems that this application depends on and have them installed with rake gems:install
    # config.gem "bj"
    # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
    # config.gem "sqlite3-ruby", :lib => "sqlite3"
    # config.gem "aws-s3", :lib => "aws/s3"
    config.gem "rmagick", :version => '1.15.12', :lib => 'RMagick'
    config.gem "rspec-rails", :lib => false

    # Only load the plugins named here, in the order given (default is alphabetical).
    # :all can be used as a placeholder for all plugins not explicitly named
    # config.plugins = [ :exception_notification, :ssl_requirement, :all ]

    # Skip frameworks you're not going to use. To use Rails without a database,
    # you must remove the Active Record framework.
    # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]

    # Activate observers that should always be running
    # config.active_record.observers = :cacher, :garbage_collector, :forum_observer

    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names.
    #config.time_zone = 'Beijing'
    config.active_record.default_timezone = 'Beijing'

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
    config.i18n.default_locale = 'zh'

    config.action_controller.session = {
      :session_key => '_xxxx_session',
      :secret      => 'fcfa0df9da9faia9fd9as8fd9as8f98as9fa9idffifa9unjvrqryq87d787b8v78xm8qfu7e8357q46q57x78erz2le89rub7q8758q7ecbr8cwe7rq8ear8ebr7x87',
      :secure      => true
    }

    config.action_controller.session_store = :active_record_store
  end
end
/////rake rails:upgrade:configuration结果结束/////




# rake rails:upgrade:gems
/////rake rails:upgrade:gems结果开始/////
# Edit this Gemfile to bundle your application's dependencies.
# This preamble is the current preamble for Rails 3 apps; edit as needed.
source 'http://rubygems.org'

gem 'rails', '3.0.6'

gem 'rmagick', '1.15.12', :require => 'RMagick'
gem 'rspec-rails'
/////rake rails:upgrade:gems结果结束/////

②确保 rails2 中使用的 plugin、在 rails3 中有替代方案. 常用的 Plugin 在这里都能找到对应的升级版本。(http://rubygems.orghttp://railsplugins.org、) 例: rails2 /vendor/plugins/will_paginate rails3 http://rubygems.org/gems/will_paginate Gemfile gem "will_paginate", "~> 3.0.4"

3.运行 rails3 工程,查找语法问题

■Ruby 1.8.7 -> Ruby 1.9.3 带来的修改点 1) 所有含有英文以外字符的.rb 文件,第一行追加

# -*- encoding : utf-8 -*-

例: Ruby 1.8

class Site < ActiveRecord::Base
  #ruby1.8不需要加magic comment
end

Ruby 1.9

# -*- encoding : utf-8 -*-
class Site < ActiveRecord::Base
  #ruby1.9需要加magic comment
end

2)NKF 被废弃 例: Ruby 1.8

NKF.nkf("-s", string)

Ruby 1.9

string.to_s.encode("sjis", "utf-8")

3)ruby1.9 中,使用 toutf8 等字符转换的方法需要 require 'kconv' 例: Ruby 1.8

site_id = "string".toutf8

Ruby 1.9

require 'kconv'
site_id = "string".toutf8

详细:https://github.com/johnnyhalife/waz-storage/issues/8

4)prec_f 被废弃 例: Ruby 1.8

1.prec_f

Ruby 1.9

1.to_f

5)Struct.members.include?方法变更 例: Ruby 1.8

struct = Struct.new(:id,:name)
struct.members.include?("id")

Ruby 1.9

struct = Struct.new(:id,:name)
struct.members.include?(:id)

6)Object#tap方法变更

class Campaign < ActiveRecord::Base
  has_many: ads

  attr_accessor :tap #属性恰巧叫tap
end


class Ad < ActiveRecord::Base
  belongs_to: campaign
end

Ruby 1.8, rails2

ad = Ad.first
ad.campaign可以正常返回campaign对象

Ruby 1.9, rails3

ad = Ad.first
ad.campaign返回nil,无法正常返回campaign对象

修改方法: attr_accessor :tap 改变量名

7)String#to_a方法被废弃 例: Ruby 1.8

"string".to_a

Ruby 1.9

"string".split

8) 字符串和数组相加结果变更

ids = [1]
str = ""
str += "id = '#{ids}'"

例: Ruby 1.8 结果 id = '1'

Ruby 1.9 结果 id = '[1]'

■Rails 2.3.16 -> Rails 3.2.13 带来的修改点

▼config、railties 相关

9)RAILS_ENV -> Rails.env RAILS_ROOT -> Rails.root

10)filter_parameter_logging 方法废弃

rails2

filter_parameter_logging :password

rails3 config/application.rb中加入

config.filter_parameters += [:password]

11)rails3 中 time_zone_aware_attributes 默认开启

rails2 time_zone_aware_attributes 默认关闭

解决方法: config/application.rb中加入

config.active_record.time_zone_aware_attributes = false

如果 updated_at、created_at 以外的 datetime 类型字段向插入本地时间,请按解决方法修改。

12)uninitialized constant ActiveRecord::RecordNotFound (NameError) (可能非共通) rails s 启动时,如果出现该错误,在 environment.rb 添加类定义

require File.expand_path('../application', __FILE__)

module ActiveRecord
  class RecordNotFound < ActiveRecordError
  end
end

▼controller 相关 13)verify 方法废弃,作为 gem 使用 解决方法: ①Gemfile 中添加 gem "verification", "~> 1.0.1" ②我的项目不适用方法①,从 gem verification 的 github 取得 verification.rb,作为共通方法放到 lib/action_controller/verification.rb 下

14)error 处理 ①rails3 中 clean_backtrace 方法废弃 ②rails3 中 rescue_action_locally 方法废弃 ③rails3 中 rescue_action 不会被自动调用

问题①②③的解决方法在下边例子中给出了。

例: rails2

rescue_from ActionController::RoutingError,
            ActionController::UnknownAction,
            ActiveRecord::RecordNotFound do
  render :partial => '/default/notfound', :layout => true, :status => 404
end

def rescue_action(exception)
  if RAILS_ENV == "development"
    logger.error(clean_backtrace(exception))
    rescue_action_locally(exception) 
    return 
  end
  case exception
  when ActionController::RoutingError, ActionController::UnknownAction, ActiveRecord::RecordNotFound
    render :partial => '/default/notfound', :layout => false, :status => 404
  else
    begin
        UserMailer.deliver_email_xxx(
          exception,
          clean_backtrace(exception),
          session.instance_variable_get("@data"),
          params,
        request.env)
      logger.error(exception.message)
      logger.error(clean_backtrace(exception))
    rescue => e
      logger.error(e)
    end
    render :partial => 'error'
  end
end

rails3

rescue_from Exception do |exception|
  rescue_action(exception)
end

def rescue_action(exception)
  new_wapper = ActionDispatch::ExceptionWrapper.new(Rails.env, exception)
  if Rails.env == "development"
    logger.error(new_wapper.full_trace)
    raise new_wapper
  end
  case exception
  when ActiveRecord::RecordNotFound
    render :partial => '/default/notfound', :layout => false, :status => 404
  else
    begin
        UserMailer.email_xxx(
          exception,
          new_wapper.full_trace,
          session.instance_variable_get("@data"),
          params,
        request.env).deliver
      logger.error(exception.message)
      logger.error(new_wapper.full_trace)
    rescue => e
      logger.error(e)
    end
      render :partial => 'error'
  end
end

④rescue_from 处理方式修改后,发生 ActionController::RoutingError、ActionController::UnknownAction 异常时, 无法迁移到/default/notfound 页面 原因: rails2: RoutingError、ActionNotFound(UnknownAction) 错误发生时,被作为异常抛出 rails3: 由于全面导入 Rack 的关系,现在的 Route 其实也是一个 Rack middleware。所以上边 2 个错误不再被当作异常抛出 (控制台中可以看到错误信息)

解决方法:

config/application.rb
config.exceptions_app = self.routes
routes.rb
match "/404", :to => "application#not_found"
application_controller.rb
def not_found
render :partial => '/default/notfound', :layout => false, :status => 404
end

参考资料: http://blog.plataformatec.com.br/2012/01/my-five-favorite-hidden-features-in-rails-3-2/

▼model 相关 15)find -> where 例: rails2

self.find(:first, :conditions => ["site_id = ? ", site_id])
self.all(:conditions => ["site_id =? ", site_id], :joins => [:ad], :group => :ad_id)

rails3

self.where(["campaign_id = ? ", campaign_id]).first
self.joins( [:ad]).wherel(["site_id =? ", site_id]).group =>(:ad_id)

16)named_scope -> scope 例: rails2

named_scope :not_delete, :conditions => ["status <> 'delete'"]

rails3

scope :not_delete, :conditions => ["status <> 'delete'"]

17)validate 写法变更 例: rails2

validates_presence_of :name
validates_presence_of :succeed_allow_site_id, :if => Proc.new{|site| site.is_succeed_allow_site == '1' }, :message => "必须输入"

def validate 
  errors.add(:base, "message")
end

def validate_on_create 
  errors.add(:base, "message")
end

def before_save
  self.begin_date = nil if self.check_date_set = "0"
end

rails3

validates :name presence=true
validates :succeed_allow_site_id,:presence =>{ :if => Proc.new{|site| site.is_succeed_allow_site == '1' }, :message => "必须输入"}

validate do
  errors.add(:base, "message")
end

validate(:on => :create) do
  errors.add(:base, "message")
end

before_save do |site|
  self.begin_date = nil if self.check_date_set = "0"
end

18)errors#on方法变更 errors#on方法在rails3中仍然存在,但意义不同了

rails2

errors.on(:height)

rails3

errors[:height].first

19)errors#invalid?方法废弃 rails2

errors.invalid?(:height)

rails3

errors.added?(:height)

20)save_without_validation! 写法变更 例: rails2

site.name = "name"
site.save(false)


site.name = "name"
site.save_without_validation!

rails3

site.name = "name"
site.save(:validate => false)


site.name = "name"
site.save!(:validate => false)

21)set_table_name -> table_name 例:

rails2

class BigSite < ActiveRecord::Base
  self.set_table_name = sites
end

rails3

class BigSite < ActiveRecord::Base
  self.table_name = sites
end

22) 通过 select 选项起别名后,rails2 和 rails3 结果不同 背景: sites 表中 id 字段为 int 型

rails2

record_id = Site.first(:select => "id as record_id").record_id 

rails3

record_id = Site.select("id as record_id").first.record_id

rails2 中 record_id 为字符串类型,rails3 中 record_id 为 int 型

23)has_many :through 删除机制改变 背景:

creative.rb 
    has_many :creative_elements, :through => :creative_element_relations
creative_element.rb 
    has_one :creative_element_relation, :dependent => :delete

在执行 creative.creative_elements.destroy_all 的时候
rails2 行为
1.删除 creative_elements 数据 2.creative_element.rb 中 dependent 语句删除 creative_element_relation

rails3 行为
1.删除 creative_element_relations 数据

解决方法:

    creative_element_relation.rb    
+       belongs_to :creative_element, :dependent => :delete
    creative_element.rb 
-       has_one :creative_element_relation, :dependent => :delete

▼views 相关 24)<% form_for %> -> <%= form_for %> Rails2

<% form_for :site, :url=>{:action => 'site_create'} do |f| %>

Rails3

<%= form_for :site, :url=>{:action => 'site_create'} do |f| %>

25)rails3 默认加 h rails2 中用 h 过滤的,rails3 中去掉 h Rails2

<%=h site.name %>

Rails3

<%= site.name %>

rails2 中想输出 html 代码的,rails3 中加 raw Rails2

<%= "<tr>" if true %>

Rails3

<%=raw "<tr>" if true %>

26)disable_with 行为变更

<%= submit_tag '追加', :name => 'add' , :disable_with => "追加"%>

解析后代码

Rails2

if (window.hiddenCommit) { 
  window.hiddenCommit.setAttribute('value', this.value); 
}else { 
  hiddenCommit = document.createElement('input');
  hiddenCommit.type = 'hidden';
  hiddenCommit.value = this.value;
  hiddenCommit.name = this.name;
  this.form.appendChild(hiddenCommit); 
}
this.setAttribute('originalValue', this.value);
this.disabled = true;
this.value='追加';
result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());
if (result == false) { 
  this.value = this.getAttribute('originalValue');this.disabled = false; 
}
return result;

Rails3

function disableFormElements(form) {
  form.select('input[type=submit][data-disable-with]').each(function(input) {
    input.store('rails:original-value', input.getValue());
    input.setValue(input.readAttribute('data-disable-with')).disable();
  });
}

说明: rails2 会新建隐藏域,controller 中 params[:add] 可以取到值 rails3 是将 disable_with 的 submit 按钮全变为不可用

解决方法: 将 rails2 解析后代码放到:onclick 中。

<%= submit_tag '追加', :name => 'back' , :onclick => "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='追加';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" %>

27)link_to 的 remote,confirm 方法失效 (非共通) 背景:rails2 时,使用集成在 rails 框架中的 prototype 完成 link_to 的 remote,confirm 功能。 rails3 时,推荐使用 jquery gem(也能完成 link_to 的 remote,confirm 功能), prototype 从 rails 框架中移出,做成了 prototype gem。

问题出现在我对上述背景不了解的时候,没有在 Gemfile 中引入 prototype。

解决方法: ①rails2 时,我的项目既使用了 prototype(Hash、escapeHtml 等) 又使用了 jquery(画面项目控制), 如果你的项目和我一样,对 prototype 依赖比较大,可以在 Gemfile 中引入 prototype。 gem "prototype-rails", "3.2.1"

解决 confirm 后,删除动作 token 验证问题 在页面中添加代码 <%= csrf_meta_tags %> 例:

<%= javascript_include_tag 'xxx' %>
<%= csrf_meta_tags %>

如果你的项目不想使用 assets 功能,请将 gem "prototype-rails", "3.2.1" 命令生成的 C:\Ruby193\lib\ruby\gems\1.9.1\gems\prototype-rails-3.2.1\vendor\assets\javascripts\ controls.js, dragdrop.js, effects.js, prototype_ujs.js, prototype.js 放到 public/javascript 下 并在页面中引入 prototype、prototype_ujs

<%= javascript_include_tag 'prototype' %>
<%= javascript_include_tag 'prototype_ujs' %>

②如果你的项目对 prototype 没有依赖,推荐使用 jquery-rails

gem "jquery-rails", "x.x.x" (请参照 rails new demo 命令生成的 Gemfile)

28)IE8 jquery 日期控件显示位置不正 (非共通) popup 弹出位置通过 jquery 的 width()、height() 来计算。 popup 弹出位置不正是由 prototype 升级带来的。 rails2 内嵌的 prototype 版本为 1.6.0.3、gem "prototype-rails", "3.2.1"升级后 prototype 版本随之升级为 1.7 prototype 升级对 jquery 的 width()、height() 方法产生影响。

解决方法: 重写 jquery 的_checkOffset 方法。

①将下边代码放到项目共同 js 中。

/* == rewrite _checkOffset method ==*/
function calDatePickerOffset(){
$j.extend($j.datepicker,{

    _checkOffset: function(inst, offset, isFixed) {
        var dpWidth = inst.dpDiv.outerWidth();
        var dpHeight = inst.dpDiv.outerHeight();
        var inputWidth = inst.input ? inst.input.outerWidth() : 0;
        var inputHeight = inst.input ? inst.input.outerHeight() : 0;
        if ($j.browser.msie) {
            var viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : ((document.documentElement && document.documentElement.scrollLeft) || document.body.scrollLeft));
        } else {
            var viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $j(document).scrollLeft());
        }
        if ($j.browser.msie) {
            var viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : ((document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop));
        } else {
            var viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $j(document).scrollTop());
        }

        offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
        offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $j(document).scrollLeft() : 0;
        offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $j(document).scrollTop() : 0;

        // now check if datepicker is showing outside window viewport - move to a better place if so.
        offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? Math.abs(offset.left + dpWidth - viewWidth) : 0);
        offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? Math.abs(dpHeight + inputHeight) : 0);

        return offset;
    }
    });

}

②在有日期控件的页面中调用 calDatePickerOffset 方法

29)link_to、redirect_to(url_for) 方法变更 (不清楚是否共通) 现象: 当点击有多个参数的 link 后,没有参数的 link 也被添加了不想添加的参数。

例: test.html.erb

link_to 'link_name', :action => 'action_name'
link_to 'link_name_multi_id', :action => 'action_name1', :id => 'first_id', :id2 => 'sec_id'

初始化进入该页面时,产生如下 url /action_name /action_name1/first_id/sec_id

当点击 action_name1 链接后,再回到该页面,产生如下 url /action_name/first_id/sec_id /action_name1/first_id/sec_id

解决方法:

link_to 'link_name', :action => 'action_name', :id => nil, :id2 => nil

PS: 这个问题不清楚是不是共通问题,有可能和我项目的 route 方式有关,如果你的项目没有这个问题,请无视。

30)number_to_currency 负数输出格式变更

<%= number_to_currency(-1000000, :precision => 2, :unit => '¥'%>

rails2 结果 -\ 100,000.00

rails3 结果 - 100,000.00

解决方法:

<%= number_to_currency(-1000000, :precision => 2, :unit => '¥', :negative_format => "%u-%n") %>

▼plugin、gems 相关 31)mysql -> mysql2 rails3 推荐使用 mysql2

database.yml rails2 adapter: mysql

rails3 adapter: mysql2

32)i18n rails3 要求 ruby1.9 下的 i18n,我这里是 i18n(0.6.1) 使用 https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale 中相应的 xx.yml 替换 config/locales/xx.yml

33)will_paginate ①:prev_label -> :previous_label ②array.paginate 发生异常 解决方法 environment.rb 添加下边内容 require 'will_paginate/array' ③修改当前页字体 div.pagination .current{ font-style:normal; }

34)rmagic 取得 filesize 写法变更

rails2

require 'RMagick'
def size(file_path)  
  if !file_path.blank?   
   img_list = Magick::ImageList.new(file_path)   
   img_list = img_list.coalesce  
   return img_list.filesize  
end

rails3

require 'RMagick'
def size(file_path)  
  if !file_path.blank?   
   img_list = File.open(file_path)   
   return File.size(img_list)
  end
end  

35) 不必再使用 ez_where(rails3 where 可以实现) rails2

conditions = Caboose::EZ::Condition.new
conditions << ["status = ?", params[:status]]
conditions << ["id = ?", params[:id]] unless params[:id].blank?

rails3

conditions = model.where("status = ?", params[:status])
conditions = conditions.where("id = ?", params[:id]) unless params[:id].blank?

36)rspec rspec (1.3.0) -> rspec (2.13.0) 修改过程

① Ⅰ.生成新的 spec_helper.rb 文件 工程目录下执行 rails g rspec:install Ⅱ.删除 lib/tasks/rspec.rake 文件 Ⅲ. 修改代码 ⅰ 文件头添加

# -*- encoding : utf-8 -*-

@logger = Logger.new("#{RAILS_ROOT}/log/test.log")

@@logger = Logger.new("#{::Rails.root}/log/test.log") 

self.fixture_path = RAILS_ROOT + '/spec/fixtures/access_tag/add/' 

self.fixture_path = "#{::Rails.root}" + '/spec/fixtures/access_tag/add/'

② 执行单个文件 rspec -cfs spec/models/access_tag/add_spec.rb 执行所有文件 rake spec 执行所有模型 rake spec:models

③ 执行单个测试时没有问题,整体执行时,部分 test_case 执行不能通过。 原因: 各个 test_case 之间没有清空数据。 修改方法: spec/spec_helper.rb

config.use_transactional_fixtures = true

config.use_transactional_fixtures = false

▼其他 37)rails3 产品模式 log,每次提交中间没有空行

/usr/local/ruby-1.9.3-p429/lib/ruby/gems/1.9.1/gems/railties-3.2.13/lib/rails/rack/logger.rb

def call_app(request, env)
        # Put some space between requests in development logs.
        if Rails.env.development?
          Rails.logger.info ''
          Rails.logger.info ''
        end

解决方法: 将 if Rails.env.development?去掉

38)incompatible character encodings: UTF-8 and ASCII-8BIT (非共通) 背景: sites 表的 name 字段是 tinyblob 类型

页面执行到<%=site.name%>时,出错。 具体原因: http://yehudakatz.com/2010/05/05/ruby-1-9-encodings-a-primer-and-the-solution-for-rails/

解决方法:

<%=site.name.force_encoding("UTF-8")%>

39)password_field 字段无法保留值。 原因及修改方法: password_field renders with nil value by default This makes the use of passwords secure by default if you want to render the value of the password_field you have to do for instance f.password_field(:password, :value => @user.password)

https://github.com/rails/rails/commit/1851af84c1c7244dc416be9c93a4700b70e801e3

现在都是从 rails3 到 rails4 了吧。呵呵

#1 楼 @jarorwar 我还在尝试 Ruby 1.8 升 Ruby 1.9 呢 你们就别呵呵了。。

ruby3 ????? rails3?

很好的文章,楼主辛苦了!

@gene_wu 谢谢你的认可. 如果能帮到不得不升级的人们一点,我就开心了

#5 楼 @microad_liy 你写的很详细了,一步一步,估计是每一个通用的问题都有记录。不知楼主是如何记录下来的呢?

楼主,幸苦了,我觉得这个东西算是很大的知识库哦。。。

#3 楼 @jarorwar Ruby 1.8,1.9 写错了。。

写 Wiki 请认真整理,并调整好排版,请将同样的内容放到同一页里面,你那一些都删除了,太乱了

数据还在的,如果你想找回重新整理,可以 @ 我

@gene_wu rails2 升级到 rails3 的中文资料比较少,调查阶段和升级阶段都比较痛苦。所以调查阶段就打算写这个帖子了,主要的步骤和遇到的问题就都留心纪录下来了。

@huacnlee 头像是你本人吗?有点像邢家栋啊! 我是从阅读者阅读方便的角度,建了很多 wiki 票,不好意思对网站的管理带来了不便。

我想找回数据,毕竟花了将近 2 天时间整理的。 我想把主 wiki 票 (http://ruby-china.org/wiki/upgrade_rails2_to_rails3wiki中,各子wiki票放到其他网站中,不知道是不是可以?) 继续放在

这个需要权限?

@guojhq 由于 wiki 被管理员删除了,所以需要权限

有点可惜

@microad_liy 文章看不到啊,LZ 有该文章其他的地址吗

@Tim_Lang 目前没有,等管理员把数据给我的,我再通知你

需要 登录 后方可回复, 如果你还没有账号请 注册新账号