Upgrade your projects to Rails 3.1

handle Rails 3.1 upgrade and asset pipeline

Upgrade2Rails31 Project

Hi, 我是 xdite。這個 projects 是因應目前 Rails 3.1 成立的升級教學網站。

Ruby on Rails 在 3.1 版加上不少新進的 feature。例如 : Assets Pipeline,內建 SCSS / Coffeescript 等等…

不過因為這次的架構變更,歷時和幅度也都不小,升級門檻有點高。

而我因為至今已經順利的升級了超過三個 Rails 3.0 -> Rails 3.1 Project,對升級歷程會發生的問題與解法已有著不錯的掌握度,因此開闢這個網站分享實戰 Rails 3.1 的一些實務心得。如果您有任何意見或勘誤,都歡迎 來信 或留言指教。

Part 1: What’s new in Rails 3.1

淺談 Asset Pipeline


  • HTTP Streaming [TODO]
  • ActiveRecord Identity Map [TODO]

Part 2: Upgrade Steps

STEP 1: Solve dependency issues / deprecated APIs

STEP 2: Apply Asset Pipeline

STEP 3: Prepare to deploy to staging / production

  • prepare production enviorment
    • install JavaScript runtime compiler
    • Git ( Compass using git version as version)
  • deploy to staging server to test results

Part 3: Fix Problems on production

  • multiple server race condition problem
  • vendor javascript plugins, ex: tinymce
  • aseets cache
  • assets uglifier
  • assets path
  • conflict rubygems
  • how to solve conflict rubygems

[Asset Pipeline] 處理 Asset Cache 導致的破圖問題

好不容易改好 asset pipeline 的東西,興致勃勃到 deploy staging / production。最常發生的掃興問題是,明明圖的路徑正確,但是圖卻破光光開不出來。

可能導致的原因有幾個:

Sendfile Header 問題

如果你是使用 apache 的話,這個選項務必要打開

production.rb
1
2
  # Specifies the header that your server uses for sending files
  config.action_dispatch.x_sendfile_header = "X-Sendfile"

如果你是使用 nginx 的話,這個選項務必要打開

production.rb
1
2
  # For nginx:
  config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

瀏覽器 Cache 問題

如果打開之後,重新 deploy 之後還是破圖,請試著清掉瀏覽器 cache 重新開啟。

Rack::Cache 問題

如果清掉瀏覽器 cache 還是無法開啟。還有一種情形可能是因為:asset pipeline 預設有 write 到 Rack:Cache 上,

而如果你的 project 上有上 cache backend 如 memcached,路徑就會被 cache 住,請記得將 server 上的 cache 清掉,再清掉瀏覽器 cache 一次,這樣多半就可以解決了….

[Asset Pipeline] Javascript Uglifier 與 min.js 相衝的問題]

這次的 Asset Pipeline 提供了 javascript uglifier 這項 feature,不只是壓縮而已,它也幫忙了將變數 uglify 掉。

不過這個功能實際使用時,我們發現一個問題。uglifier 提供的壓縮變數也是使用 a,b,c,d,e,f,g 等規則。

這會造成…

將 jquery.min , jquery-ui.min 大包的 library 丟進去與其他 js 一起壓時,壓出來的 js 是異常的。( xx is undefined )

因此有一些 function 就此爛掉…

解法 : 別把 jQuery 也丟進來壓縮

如果你有使用到 jQuery 的話,別照著官網把 jquery.min 丟進來壓,應該使用 Google 提供的 jQuery 另外拆出來獨立載入。

自己手寫的才使用 uglifier 壓縮打包。

[Asset Pipeline] 處理 Vendor 類 Js Plugin 如 TinyMCE 的問題

一般來說,簡單的 js plugin 還蠻好掛上 Rails 3.1 的 projects。但是複雜如 TinyMCE 這種套件呢?

相信我,一定可以把你搞到快往生。

因為 TinyMCE 是採用動態載入的形式,這也使 asset pipeline 提供的 precompile + fingerprinting feature 與它格格不入。

而一般的 TinyMCE 資料夾底下通常會放置了很多 plugins 與 themes,這也使得 assets pipeline 在 load assets 時格外困難。(你總不想很蠢的直接在 production.rb 裡面一個一個指名路徑吧。)

解法: 安裝 digestion

然後在 Gemfile 下 enable 它

Gemfile
1
gem 'digestion'

請注意,別把它扔進 Gemfile 裡的 assets group 裡,這會使得這個 gem 在 production 一點作用也沒有。

然後在 production.rb 裡加入這兩行。

production.rb
1
2
config.assets.digest_exclusions << "tiny_mce/*"
config.assets.precompile << "tiny_mce/*"

就能解決你的問題了…

===

P.S. 若你很懶惰的話,也可以直接安裝 tinymce-rails 這個 gem(感謝 @ihower 提供 ,原理類似。只不過我們的狀況有太多 customized plugin,必須用 digestion 的方法繞過。

[Asset Pipeline] Multiple Server 跑 Rails 3.1 Asset_pipeline,precompile 會遇到的 Hash 問題

我們有兩台以上的機器做 HA,但兩台的 production 壓出來的 asset 的 digest url 卻不一樣。

造成使用 CDN cache asset 時會有 race condition 問題,全站 asset 脫光光。

本來懷疑是 deploy precompile asset 的順序問題,後來調整了也沒用。找了半天換手請同事 @vincent 找,也研究了不久才抓到罪魁禍首:

1
2
3
4
5
#header {
   position: relative;
   z-index: 99999;
-  background: image-url("/assets/images/header-background.png") ;
+  background: url("/assets/images/header-background.png");

這一段在 SCSS 裡面作用是類似的。

但在擁有多台 production 時,image-url 產生的 png 路徑與 url 產生的路徑卻會不同。image-url 產生出來的路徑是動態的…

而 Rails 的 digest url 路徑 是根據 hash css 內容所算出來的,因此不同兩台機器,很有可能就產生出不同的 url。因此 CDN 就會吃到白的 CSS (404) 了…

解決方式

就是把有用到 image-url 的部份通通改用 url 就可以了。

後來得知是 helper 問題後,把 image-url 當關鍵字丟進去 google 找,也發現有人已經在 sass-rails 這個專案哀號過了 XD。