Rails4 升级第一弹

最近在做rails4升级的工作,过程中遇到了很多问题,这里记录下来供大家参考,个人建议如果还没有

用过rails4的,可以自己建一个blog工程,看一下整体结构跟rails3有什么不同的地方,哪里需要修改,

另外去官方网站把rails4升级的change log简单的过一遍,google以下其他人的升级步骤和遇到的问题及

解决方案

 

下面是为在升级过程中遇到的问题及解决方案,链接为参考的资料,另外部分代码做了简单的处理,只为

说明问题,未完待续,关于发布和测试的正在整理中。。

 

------------------------------------------------------------------------------------------------------------------------------------

另外欢迎关注个人微信订阅号:ruby程序员, 方便大家坐车上下班无聊的时候,共同学习ruby & rails

-------------------------------------------------------------------------------------------------------------------------------------

 

**修改rails为4.1.5,及依赖的gem包 升级rails关联组建的版本号到4**

 

```ruby

    -gem 'sass-rails', '3.2.6'

    -gem 'coffee-rails', '3.2.2'

    -gem 'uglifier', '2.1.2'

    -gem 'cells', '3.8.8'

    -gem 'rails', '3.2.15'

    +gem 'rails', '4.1.5'

    +gem 'sass-rails', '~> 4.0.3'

    +gem 'coffee-rails', '~> 4.0.0'

    +gem 'uglifier', '>= 1.3.0'

    +gem 'cells', '3.9.1'

```

 

  **添加如下gem包,处理rails4新增特性,比如rails4去掉了observers和参数检查的特性**

 

  ```ruby

    +gem 'protected_attributes'

    +gem 'rails-observers'

    +gem 'mongoid-observers'

    +gem 'actionpack-page_caching'

    +gem 'actionpack-action_caching'

  ```

 

  **执行bundle update更新到最新的版本,如果发生依赖冲突,则暂时去掉版本号**

 

  ```ruby

    -gem 'mongo', '1.9.1'

    -gem 'mongoid', '3.1.4'

    -gem 'bson_ext', '1.9.1'

    +gem 'mongo'

    +gem 'mongoid'

    +gem 'bson_ext'

  ```  

  **例如:db-charmer发生了版本冲突,则去掉版本1.9.0, 更新到最新的版本**

 

```ruby

      In Gemfile:

        db-charmer (= 1.9.0) ruby depends on

          activesupport (< 4.0.0) ruby

    

        rails (= 4.1.5) ruby depends on

          activesupport (4.1.5) 

```

   **启动应用,根据log来检查所有gem包的加载是否报错,根据错误提示解决**

有问题的几个gem

 

```ruby

    #client_side_validations 没有支持rails4的版本,暂时去掉

    #gem "client_side_validations"

 

    #替换为rails4支持的版本,否则会报错

    -gem "galetahub-simple_captcha", '0.1.5', :require => "simple_captcha"

    +gem 'simple_captcha2', require: 'simple_captcha'

 

    -gem 'pry-debugger' 

    +gem 'pry-byebug' 

```

 

## Gem Install Debugger Error

 

  No such file or directory @ rb_file_s_stat - ./213/ruby_debug.h (Errno::ENOENT)

 

  Ruby 2.1.2 isn't supported by debugger, unfortunately. Instead, 

  use the byebug gem. See this discussion for more details.

 

  https://github.com/cldwalker/debugger/issues/125#issuecomment-43353446

 

  修改gem 'pry-debugger' 为  gem 'pry-byebug' 

 

 

## rails4.1 Rails 4.1 breaks Cells

 

  uninitialized constant Cell::Base::Layouts

 

  修改cells版本为3.9.1 gem 'cells', '3.9.1'

 

  https://github.com/apotonick/cells/issues/190

 

 

## rails4 强制加载路由文件

 

  undefined method `concat' for nil:NilClass (NoMethodError)

 

  在rails3中,config.paths['config/routes'].concat %w{admin schools} 

  

  在rails4中,使用Rails.application.reload_routes!替代

 

 

## 替换解析器

 

  去掉ActiveSupport::XmlMini.backend = 'Nokogiri', activeSupport4,默认使用nokogiri解析xml文件

 

  application.rb

    ```ruby

      # 替换解析器

      +config.gem 'yajl-ruby', :lib => 'yajl/json_gem'

      -ActiveSupport::XmlMini.backend = 'Nokogiri'

      -ActiveSupport::JSON.backend = 'yajl'

    ```

 

  undefined method `backend=' for ActiveSupport::JSON:Module (NoMethodError)

  Yail advertises as much faster than JSON and YAML

  ActiveSupport::JSON.backend = 'yajl' #activeSupport4 去掉了backend方法

 

  http://stackoverflow.com/questions/3073711/whats-the-best-way-to-use-yajl-ruby-with-my-rails-project

 

 

## 更新配置文件 config/environments/*.rb

 

  注释掉: config.active_record.auto_explain_threshold_in_seconds = 0.5

 

  新增:  config.eager_load = false

 

 

## mongoid配置文件

 

  去掉配置文件mongoid.yml中的  

  allow_dynamic_fields: true

  identity_map_enabled: true

 

  合法的配置选项有:

  :include_root_in_json, :include_type_for_serialization, :preload_models, :raise_not_found_error, 

  :scope_overwrite_exception, :duplicate_fields_exception, :use_activesupport_time_zone, :use_utc

 

  在升级Rails4的同时, mongoid 也从3.1.4 升到4.0.0, 运行rails server 命令, 结果报错 说:allow_dynamic_fields 是无效参数。

  查看mongoid的change log, 发现 allow_dynamic_fields 已经从配置文件中 移除了, 

  如果想继续使用动态属性, 只需要在model 中添加

 

  include Mongoid::Attributes::Dynamic

 

  http://www.ml-china.org/blog/42

 

## 修改模型关联关系,去掉:conditions, order等rails3中的方法,在rails4中使用 ->{} 代替

    

```ruby

  -  has_many :ws, :class_name => "B", :conditions => "b_type = 'b", :order => "status desc"

  -  has_many :ss, :class_name => "S", :conditions => "s_type = 's'", :order => "status desc"

  +  has_many :ws, -> { where("b_type = 'b'").order("status desc")}, :class_name => "B" 

  +  has_many :ss, -> { where("s_type = 's'").order("status desc")}, :class_name => "S"

```

 

## validates 正则表达式

 

  check_options_validity': The provided regular expression is using multiline anchors (^ or $)

  rails4中validates不支持 ^ 和 $ , 替换成\A 和 \z

 

```ruby

  -  ACCOUNT_EMAIL_FORMAT = /^\s*#{FORMAT}\s*$/

  +  ACCOUNT_EMAIL_FORMAT = /\A\s*#{FORMAT}\s\z/

```

 

  方式一,使用\A \z替代 ^ $

  validates :mobile_number, :format => { :with => FORMAT }, :allow_blank => true

  方式二,使用multiline: true说明

  validates :content, format: { with: /^Meanwhile$/, multiline: true }

 

  http://stackoverflow.com/questions/17759735/regular-expressions-with-validations-in-ror-4

  http://guides.rubyonrails.org/security.html#regular-expressions

 

## rails4 has_many uniq

 

  uniq在rails4中的关联关系中需要放在一个block中,而且作为has_many的第二个参数

  The uniq option needs to be moved into a scope block. 

  Note that the scope block needs to be the second parameter to has_many 

  (i.e. you can't leave it at the end of the line,

  it needs to be moved before the :through => :donations part):

 

```ruby

  rails3: has_many :ds,  :through => :ds, :uniq => true

  rails4: has_many :ds, -> { uniq }, :through => :ds

    

  rails3: has_many :ds, :through => :ds, :uniq => true, :order => "name", :conditions => "age < 30"

  rails4: has_many :ds, -> { where("age < 30").order("name").uniq }, :through => :ds

```

  http://stackoverflow.com/questions/16569994/deprecation-warning-when-using-has-many-through-uniq-in-rails-4

 

## mongoid扩展

 

  mongoid 从3.1.4升级到4.0.0, 查看源代码,发现mongoid的结构有了比较大的变化,那么我们在

  3.1.4上做的扩展在这里就不适用了,主要从以下几个方面来进行检查

 

  1.文件结构

 

```ruby

  3.1.4: Mongoid::Persistence

  4.0.0: Mongoid::Persistence::Updatable

```

  updatable是mongoid4抽象出来的一个module,原来放在Persistence这个module里的方法,一部分放到了

  updatable中,重写方法的时候,注意函数的位置

  2.函数

 

```ruby

    def update_attributes_with_format(attributes = {}, options = {})

      update_attributes_without_format(attrs, options)

      alias_method_chain :update_attributes, :format

    end

```

  扩展的时候重写了update_attributes方法,但是mongoid4.0.0版本中,已经去掉了options参数,这里也需要去掉

 

  3. change logs

  mongoid去掉了IdentityMap,如果重写了IdentityMap相关的方法,就需要重新根据mongoid4.0.0

  change log:

  * Scopes and default scopes must now all be defined within lambdas or procs.

  * `skip_version_check` config option was removed.

  * IdentityMap removed. (Arthur Neves)

  * Eager load rework. Eager load now doesnt need the identity map to load

    related documents. A set of preloaders can eager load the associations

    passed to .includes method. (Arthur Neves)

 

  https://github.com/mongoid/mongoid/blob/006063727efe08c7fc5f5c93ef60be23327af422/CHANGELOG.md

  https://github.com/mongoid/mongoid/issues/3406

 

 

## rails4 加载多个路由文件

 

  rails3中,项目比较大,很多路由被单独存放在 config/routes/*.rb 中, 

  加载的时候,在application.rb文件中使用下面的代码进行加载

  -config.paths['config/routes'].concat %w{aa bb cc ...}

 

  而在rails4中,Rails::Engine.paths 去掉了 ["config/routes"] 的key

  解决办法,在config/routes.rb 的首行进行加载

  +Dir[Rails.root.join("config/routes/*.rb")].each{|route| load route}

 

  http://stackoverflow.com/questions/18902878/how-to-reload-routes-config-routes-in-rails-4

 

## rails 路由

 

  rails4中如果使用match,必须指定http方法 

  match 'homejson', to: 'afterwork#home_json', via: [:get, :post]

 

  否则 需要替换match方法为get

  -        match 'like'

  +        get 'like'

 

```ruby

  get 'file/:file_id', action: 'file', as: 'file'

  delete 'file/:file_id', action: 'delete_file', as: 'file'

```

  上面的这种配置,在rails4中会报以下错误, 解决办法是去掉最后一个,rails4会根据上一个自动添加

  You may have defined two routes with the same name using the `:as` option

 

  + delete 'file/:file_id', action: 'delete_file'

 

## find_or_create_by find_or_initialize_by

 

```ruby

  rails3:

    User.find_or_create_by_name('XXX')

        

  rails4:

    User.where(name: 'XXX').first_or_create

    User.where(name: 'XXX').first_or_create!

        

  rails3:

    User.find_or_initialize_by_name('XXX')

   

  rails4:

    User.where(name: 'XXX').first_or_initialize

```

 

  http://snippets.aktagon.com/snippets/620-rails-find-or-initialize-and-find-or-create-methods-are-deprecated

 

     

## client_side_validations

 

  client_side_validations 3.2.6 不适用rails4,暂时先去掉

 

## preloading : no such column问题

 

```ruby

    class Corp <  ActiveRecord::Base 

      has_many :ins, ->{where("corp_enus.category=2")}, class_name: "CorpEnu"

    end

```

 

  方式一: 使用includes, 添加references

  rails3

  includes(:ins).where("corp_enus.enum_value1 = ?",id).order("followers desc").limit(limit)

  rails4, 添加.references(:industries)

  includes(:ins).where("corp_enus.enum_value1 = ?", id).order("followers desc").limit(limit).references(:ins)

 

  方式二:使用eager_load替换includes

 includes(:ins).where("corp_enus.enum_value1 = ?",id).order("followers desc").limit(limit)

 eager_load(:ins).where("corp_enus.enum_value1 = ?",id).order("followers desc").limit(limit)

 

  http://api.rubyonrails.org/v4.0.1/classes/ActiveRecord/QueryMethods.html#method-i-eager_load

  http://api.rubyonrails.org/v4.0.1/classes/ActiveRecord/QueryMethods.html#method-i-preload

  http://api.rubyonrails.org/v4.0.1/classes/ActiveRecord/QueryMethods.html#method-i-includes

  http://blog.arkency.com/2013/12/rails4-preloading/

 

## Mongoid::Errors::InvalidField 

 

  错误信息

  Mongoid::Errors::InvalidField - 

  Problem:

    translation missing: zh-CN.mongoid.errors.messages.invalid_field.message

  Summary:

    translation missing: zh-CN.mongoid.errors.messages.invalid_field.summary

  Resolution:

    translation missing: zh-CN.mongoid.errors.messages.invalid_field.resolution:

 

```ruby

  class AuthorizationMongo

    include Mongoid::Document

    include Mongoid::Timestamps

    

    field :deleted, type: Boolean, default: false

  end

```

  修改字段 deleted 为 is_deleted, 问题解决

 

## SystemStackError - stack level too deep

 

  错误信息:

  actionpack (4.0.0) lib/action_dispatch/middleware/reloader.rb:70:in `'

  可能是写法问题导致的,调试发现把user.name 改成 user[:name]就不会出现这个错误

  但是不清楚为什么

  代码:

 

```ruby

  def link_to_user(user, opt={})

      return if user.blank?

      inner = opt.delete(:inner)

      opt[:title] ||= "#{user[:name]}, #{user[:headline]}"

  end

```

  把user.name 改成 user[:name]

 

## uninitialized constant Mongoid::Observer

 

  mongoid4去掉了Mongoid::Observer, 所以找不到Mongoid::Observer

  在Gemfile中添加gem 'mongoid-observers'问题解决,用法和原来一样

 

```ruby

    # 资料完整度的观察者

    class Profile::ProfileCentObserver < Mongoid::Observer

      observe :user_mongo

      def after_save user 

      end

    end

```

  https://github.com/chamnap/mongoid-observers

你可能感兴趣的:(升级,Rails,rails4)