Rails 升級 Rails 4 請先停看聽 (災難帖)

xdite · 2013年06月27日 · 最后由 bpw11320 回复于 2013年10月29日 · 9832 次阅读

http://blog.xdite.net/posts/2013/06/27/upgrade-rails4-danger/

TL; DR: Rails 4.0.0 有地雷,建議修完所有 depcrapted warning 再從 rc1, rc2 升級,不然會有大災難。

上個禮拜跟同事做了個 Markdown Blog Service Provider : Logdown。介紹請看這裡。Logdown 是用 Rails 3.2.13 寫的。適逢昨日 Rails 4.0.0 釋出,於是手癢癢就想幫 Logdown 升級…

上個月我曾經寫過兩篇文章:

該踩的雷我都中過了,也知道怎麼 patch 常見的地雷,閃過去….

不過我膝蓋還是中了一箭了…orz

地雷一:強制 raise error

Rails 4 改變最大的有幾個重點:

  1. 拿掉 attr_protected,改用 strong parameters
  2. scope 改用 -> {}
  3. routes 建議大家棄用 match,而用更精確的 get , post

well, 在 4.0.0 版,如果你還在用 match 的話,Rails 除了 warning message 還會直接 raise error。網站會直接跑不起來,而不是像 beta 的向下相容。而且一些行為也會強制禁掉,如 Logdown 其實有兩個 root :to,其中一個跑 contraint 偵測是否有 user 而導到後台。

Rails 4 是直接禁掉這樣的 syntax 讓你跑不起來。

不過這個還算好的警告手段。直接爛掉雖然有點 annoying,但是你知道 patch 掉就沒有後遺症了....

地雷二:改變行為

這件事我真的覺得最扯....。但也可以預見未來可能有一些災難發生。

Rails 4 beta 建議大家 scope 改用 -> {}。並且有警告 Message 通知你必須改變,但撈出來的 query 還是向下相容,也就是執行結果是正確的。

Rails 4.0.0 版 建議大家 scope 改用 -> {}。並且有警告 Message 通知你必須改變,但撈出來的 query 行為改變,也就是執行結果是錯誤的。

這件事讓到底有多嚴重,我的 post.rb 是這樣設計的:

class Post < AR
  scope :recent, order("id DESC")
end

而在 Logdown 的 Dashboard 裡面,我的後台 index action 是這樣設計的

class Account::PostController < AC
  def index
    @posts = current_users.posts.recent
  end
end

正常的行為,生出來的 query 是這樣的(撈出我本人的所有文章):

Post Load (11.3ms)  SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 3 ORDER BY id DESC LIMIT 50 OFFSET 0

到這邊都沒什麼問題。

本來我改好程式,在 local 測一測看起來沒什麼問題,(Rails 4 最大的改動通常是 update_attributes 會需要修,query 通常不太需要修)…也沒 raise error。還好我今晚是先 deploy 到 staging 去測。deploy 上去差一點噴茶....

我個人的 Dashboard 竟然出現了(全站文章) ……orz…..WTF…

在 local 重新測試才發現:

如果你沒把 scope 改成

class Post < AR
  scope :recent, -> { order("id DESC") }
end

那麼…在後台

class Account::PostController < AC
  def index
    @posts = current_users.posts.recent
  end
end

生出來的 query 會長這樣

Post Load (1.2ms)  SELECT `posts`.* FROM `posts` ORDER BY id DESC LIMIT 50 OFFSET 0

齁齁,所有條件失效,撈全站文章給你。簡單的 query 都這樣,複雜的 query 我不敢想像。( -> { } 的新預設寫法席卷了一大堆設計,而且一堆 plugin 還在用 舊 query … )我已經可以預見這會產生多大的災難了....

重點是,你還不能回報這是 bug,畢竟人家都已經叫你換成 -> {},誰叫你不換勒?

地雷三:管太多…

我在 deploy 的時候,遇到 Asset compile 不過的狀況。sprockets 一直報錯:

Asset logical path has no extension: README

WTF,我從沒在之前的版本看過這個。在網路上搜尋了一下發現是這個 issue..:

https://github.com/sstephenson/sprockets/issues/347

意思就是 sprockets 連你的 README 有沒有加 .txt 都要管啦 -_-。然後維護者不想修,叫大家自己去找 workround…

所以如果你的 app/assets/javascripts app/assets/stylesheets 下如果有沒有副檔名的檔案,compile 就不會過。你會想說 not big deal,自己改成多加 .txt 或 .md 就好了…

沒這麼簡單。一堆 3rd party 的 css / js ..不僅有 …..README…還有 LICENSE…還有 CHANGELOG….XDD

齁齁齁,感覺很精彩了吧。沒關係,這都可以加 .txt。頂多是 CSS / JS 界的 repo 這陣子會被 Rails developer 群騷擾而已。更精彩的是 Makefile….這到底是要怎麼閃 XD

( 剛剛網路上找 solution 看到一堆慘案 …)

Bower 已經身亡,這裡是解法

Summary

如果你是從 Rails 4.0.0beta1 或者是 Rails 4.0.0rc1 升級,務必停看聽…

Rails 4.0.0 跟你想得很不一樣 …orz

Rails 的升级总是让人痛苦。插件对 Rails 版本的依赖,真的是一个最让人头疼的问题。

又是 Sprockets……服了,等我找到纯前端的静态资源管理办法,一定第一个弃用他

我去,我正在用 4.0 写一个新项目,这坑也太大了点.....

#4 楼 @fresh_fish 用应该没那么多问题吧,lz 主要说的是升级。

#5 楼 @zgm 当然有啦,很多 gem 都没这么快跟上来升级,尤其是【地雷三:管太多】,这个巨坑啊

#6 楼 @fresh_fish 那这个不是 rails 自身的问题。

#3 楼 @robbin 不能同意的太多,rails3 的时候,有些大牛离开时就吐槽过这些个核心维护人员,说他们不靠谱的很。

是不是把错误的版本 release 出来啦。。。 如果 Rails 4 不肯修这些 bug 的话 那倒是也是巨大的商机 会有很多 Rails 4 Xxxx 版本出现的。。。嗯 赶紧开发去。。

唉,Rails core team 确实有点不靠谱了,竟然会有语法错误的问题出现在 master 分支,orz....

@tumayun 在哪一個 commit ...?

@xdite 哈哈 被我捡漏了

#3 楼 @robbin 请问 padrino 多线程下是否遇到过问题,类似 HttpRouter::DoubleCompileError 的错误,参见:https://github.com/padrino/padrino-framework/issues/863

#14 楼 @tumayun 看来以前用火箭太习惯了

@huobazi 啥意思,没明白

@huobazi 哈哈 火箭,明白了,是呀 换写法还是需要一段时间过度

asset pre compile 嘛,我一路将各种 assets gem 的换成 github 上的最新版本或者自己 fork 一份改一下就差不多了,目前遇到最坑的是 compass-rails,貌似它的 rails4 分支还没动过……

别的都好说,改改就好了,但“連你的 README 有沒有加 .txt 都要管”,这就抓狂了,作者这是怎么想出来的啊

這是 compass-rails 的解法...

group :assets do
  gem "compass-rails",    github: "milgner/compass-rails", ref: "1749c06f15dc4b058427e7969810457213647fb8"

end

#10 楼 @tumayun

唉,Rails core team 确实有点不靠谱了,竟然会有语法错误的问题出现在 master 分支,orz....

哈 这个太过分了。。竟然没测试就 Release 了。。。

脚步随时更紧,升级的时候其实也没那么难,看 Ruby China 这份代码从之前 3.0 升级到了现在的 4.0

我觉得重点是不要写一些“奇特”的东西,尽可能使用标准通用的,这样不容易遇到坑

#22 楼 @xdite 这个我已经在用了,只是吐嘈下官方的 rails4 分支挂羊头卖狗肉……

#24 楼 @huacnlee 有些没办法的啊,比如 mongoid 的那些 atomic operations,API 全改了,只能一个个跟着改……

同意 @huacnlee 的。儘量使用「標準」寫法。以免掉坑...

#24 楼 @huacnlee 我从 3.2.13 升 rc1,基本无痛,就是 assets 的问题要等一些 gem 更新解决,现在各个 gem 都跟进了。非常赞同老大说的写标准通用的代码的做法。 #27 楼 @xdite 一直关注 Rails 4,railscasts 出了教程(Upgrading to Rails 4),基本上像 scope 这些问题都有强调。我记得之前看过一些资料,说的是 scope 里使用 lambda,那里也就比较关注这个,因为当时自己不懂这东西……

我觉得前面两个坑还可以接受,但是第三个 管太多 那个就太变态了。扯淡!

歪个楼。。纠正下是workaround不是workround ...

匿名 #32 2013年07月03日

#3 楼 @robbin 请问 padrino、sinatra 是什么时候的产品?国内大牛开发的?我刚开始学习 rails,ruby 方面的 web 开发应该选择什么框架?请指点一二,谢谢

@yunzifeiyu sinatra bug 比较少,padrino 基于 sinatra 在我看来就像一个高度定制的 rails,rails 教程比较多,如果英文不错学 padrino 不错,它的教程比 rails 规范。

Cancan 挂了,有解法没?

#24 楼 @huacnlee 同意,写奇怪的东西并不代表你写得有多高深,很容易一眼看懂就实现了业务逻辑才是正确得做法

#34 楼 @hardywu 不要用 load_and_authorize_resource,用 authorize!

#36 楼 @imlcl 可以用 load_and_authorize_resource 的啊,我这好好的没啥问题……

#37 楼 @aptx4869 呃,我发现不行。。。不过我当时在 rails 4.0.0.rc1 时就不用这方法了…不知现在是不是又可以了…

#38 楼 @imlcl 真管用。谢谢。

#38 楼 @imlcl authorize! :index, @posts 貌似不管用。

#39 楼 @hardywu 哦原来有这个问题啊,不过大概因为我用的是"非标准"做法,反而都绕过去了…… working example:

class AttachmentsController < ApplicationController
  before_action :authenticate_user!
  before_action :create_attachment, only: :create
  load_and_authorize_resource
  respond_to :html, :json

  def index
    @attachments = current_user.photos.recent_upload.limit(10)
  end

  def create
    @attachment.save
    respond_with @attachment
  end

  def destroy
    @attachment.destroy
    respond_with @attachment
  end

  private

  def attachment_params
    params.require(:attachment).permit(:file)
  end

  def create_attachment
    if current_user
      @attachment = current_user.photos.build(attachment_params)
    end
  end
end

#41 楼 @hardywu 晕,sorry,我用 authorize_resource 的,authorize! 好像暂时没有用到。@xdite 的 blog 有篇《Cancan 實作角色權限設計的最佳實踐》(共三篇) http://blog.xdite.net/posts/2198-cancan-rule-engine-authorization-based-library-1 应该会有所帮助吧,虽然我自己也没有用什么高级的功能…… 我试过 rolify + cancan 的组合,感觉还不错

补充: 找了一下,这个对你有帮助https://github.com/ryanb/cancan/wiki/authorizing-controller-actions

#43 楼 @imlcl 我也试出来了。。authorize_resource解决了create action validation 失败后权限出问题的情况。

#22 楼 @xdite 更新不下来 地址错误额。

iamroody Rails 4.0.0 正式发布了 提及了此话题。 04月03日 10:56
需要 登录 后方可回复, 如果你还没有账号请 注册新账号