很久一段时间以来,我们使用的都是 Rails3.2 + Mongoid3,虽然 Rails4 发布已经快一年的时间了,但由于 mongoid3 不能支持 Rails4,所以升级就一推再推,不过终于在近期 Mongoid 发布 4.0 以后完成了这次期盼已经的升级。心情是兴奋地,不过过程还是曲折的,不少细节,只看升级文档,或者 google,不看源码还是真心不好解决。本文不是升级指导,因已经有很多文章,本文将对这次升级遇到的问题做个简单的介绍,包括了 Rails,Mongoid,Capistrano。
每次升级有两个前提必须保证才可以稍微顺利一些:
1. Strong Parameters 它主要用来增强 mass assignment 的安全性,Rails3 中通过使用 attr_accessible 在 model 层面进行控制,没有声明为 attr_accessible 的属性不能用 mass assignment 来赋值。但通常来说这个赋值的行为发生在 controller 级别,所以 Strong Parameter 将这样行为的限制上升在 controller,并通过下面的格式来进行限制。
params.permit(:name, {:emails => []}, :friends => [ :name, { :family => [ :name ], :hobbies => [] }])
这其中定义了三种格式的参数类型,其中期望 emails 的值为 Array 的类型,而 friends 是一组 Array 的资源,有 name 属性,family 的值为 Array 并含有 name 属性,hobbies 的值则是 Array 类型。
2. controller 测试异常缓慢 我们使用的 MiniTest,升级完成后运行 controller 测试时,非常非常的缓慢。后来发现当测试中 request 请求成功后,停在了在 render layout 那这一步,需要将近 5 分钟才可以完成。测试本身是成功的,而这 5 分钟也与 asset precompile 的时间类似。
Rails 4 no longer sets default config values for Sprockets in test.rb, so test.rb now requires Sprockets configuration. The old defaults in the test environment are: config.assets.compile = true, config.assets.compress = false, config.assets.debug = false and config.assets.digest = false.
其中最主要的设置为
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = true
此项设置的主要目的是当找不到 precompiled 的 asset 时是不是需要时时编译。当然,我们是不需要这样的设置的,所以当设置为false
时就解决了这个问题。
不过有个问题还是不明白,之前的默认值为true
是如何正确工作的呢?
3. 测试单独通过,rake test 失败 使用 rake 运行所有测试时,抛出
TypeError: compared with non class/module
无法定位是什么问题,好在有人遇到了一样的问题 https://github.com/freerange/mocha/issues/199,不要使用 ruby2.0.0-p0,改为 2.0.0-p353 就好了。
4. Capistrano 原先使用的是 Capistrano2,由于 Capistrano3 做了很大的改动,所以为了平稳尽快完成 Rails 的升级,对 Capistrano 尽量做到最小的改动,这篇文章一定要看。其中两点最重要:
需要注意的是,升级之后在部署过中可能会看到一些 err 输出,实际上是 Capistrano 将 info 的输出信息作为 err 打印到 console 了。参见这里INFO messages while asset precompiling treated as errors
5. 嵌入的支持
Rails4 会在 response 的 header 里增加一下的默认值,其中SAMEORIGIN
限定了 iframe 在同一个 domain 中可以使用。如果取消这一限制有两种做法,一个是在下面的全局配置中将X-Frame-Options
改为ALLOWALL
。当然,如果只想针对单个请求,可以将这个设置在该请求的 response 中去除response.headers.except! 'X-Frame-Options'
。
config.action_dispatch.default_headers = {
'X-Frame-Options' => 'SAMEORIGIN',
'X-XSS-Protection' => '1; mode=block',
'X-Content-Type-Options' => 'nosniff'
}
6. Mongid 中使用 Only 后的限制
升级 Mongoid4 后,使用 Only 后的 model 对象将为只读,不可以再修改,否则会抛出下面的异常。检测 document 是否为只读可以直接在 model 上调用readonly?
。在 Mongoid3 中没有这样的限制
Mongoid::Errors::ReadonlyDocument:
Problem: Attempted to persist the readonly document 'Entry'.
Summary:
Documents loaded from the database using #only cannot be persisted.
Resolution:
Donot attempt to persist documents that are flagged as readonly.
另外使用 only 后,如果直接读取没有加载的属性,将抛出异常ActiveModel::MissingAttributeError: Missing attribute: 'not_load_attr’
。在 Mongoid3 中返回 nil。
下面是一些升级指导的链接
原文来自我的博客,不正确的地方欢迎大家交流。