Rails 3.1 RC 發佈: 重點導覽

Update(2011/8/31): 正式釋出! Rails 3.1.0 has been released!

來整理一篇 Rails 3.1 重點,花了點時間看過一遍 Changelogs (TL;DR;)。

新的預設 jQuery

jQuery: New Default: 官方的說明

jQuery 取代 prototype.js 成為新的預設 JavaScript 函式庫。另外,RJS 也從核心中被移出成為 Plugin。還記得當年令人興奮的 RJS 功能,可以很方便的寫簡單的 Ajax 效果,如今又回到直接寫 JavaScript 才是王道。

Assets pipeline

RailsConf 2011, David Heinemeier Hansson: 今年 DHH 在 RailsConf 的演講,重點就在介紹 Assets pipeline。

靜態檔案成為一級公民了,Rails 3.1 透過 Sprockets 打包和壓縮靜態檔案,也支援編譯 SassCoffeeScript。細節請參考我書的 Assets 一章

將 CoffeeScript 納入預設有不少爭議,畢竟用 CoffeeScript 實在又多了學習負擔,不是這麼多人喜歡。不過它其實只是 Gemfile 預設載入的一行而已,如果不用拿掉即可。

HTTP Streaming

HTTP Streaming 功能是 Rails 3.1 的一個實驗性突破,可以在 render 樣板的同時,就同時開始下載資料來節省時間。原理是 HTTP 1.1 協定中的 Chunked transfer encoding 傳輸機制。我推薦可以看看 Facebook 的 BigPipe 應用其實就是這個技術。

這功能預設是關閉的,而且也不是打開設定就馬上可以享受到。因為 render 的流程不同了,本來可以先 render template 再套 layout 的,用 streaming 的話是改從 Layout 先開始,由上往下一行一吐出結果就丟給瀏覽器,因此需要搭配注意的細節不少,像是要用 Ruby 1.9、網頁伺服器要支援、template 中不能讀取 layout 中的變數、使用 provide helper 取代 content_for、Controller 的操作必須盡可能的改成 Lazy method (也就是真正耗時的動作得實際發生在 View 中,例如 SQL query,不然時間卡在 Action 裡沒進到 View 就沒辦法提早傳結果出去啦。好加在 ActiveRecord 的 Query 都已經是 Lazy method 了),最後所有你用到的 Rack Middleware 層都必須支援 HTTP Streaming,萬一其中有 Middleware 需要等 response 完整的 body 內容才能處理,那麼就會卡住而失去 Streaming 提早送資料給瀏覽器的意義。

Migration

Reversible migration:新的 change 方法可以不需要分開寫 up 跟 down 了,Rails 會自動對應出 down 的操作,猜不出來的時候才會要你補寫 down 方法。

還有,Migrations 內統一改用 Instance methods 而不是 class methods 了,寫 def up 和 def down 即可,不需要 def self.up 和 def self.down。

Rack::Cache

加入了 Rack-cache middleware ,搭配 #expires_in, #fresh_when, #stale with :public => true 等方法,並使用你設定的 Caching store 來存放資料 (例如memcached)。

注意到因為有了 Rack::Cache,原本 Controller 的 Page caching 被移除不需要了。

採用 Rack-caching 真正的重點倒不是在於增加效能,而是在於它讓你無痛就開始寫符合 HTTP caching 標準協定的程式,讓你之後有流量需求時,可以很彈性地轉換到真正的 HTTP caching 伺服器上,例如 Varnish。詳情請參考Rack-cache FAQ

Mountable Engines

Engine 被改的更為獨立,可以擁有獨立的 routes 和 namespace。請參考 API 文件,或是這篇簡介 Mountable engines in Rails 3.1 beta: getting started

ActiveRecord/ActiveModel 相關

  • 採用 SQL Prepared statements 了,增加複雜 SQL query 的效能。
  • Mass assignment 可以設定 attr_proected 和 attr_accessible 因應不同角色而有不同限制,挺不錯實用的功能。詳見 API 文件
  • Custom ActiveRecord Attribute Serialization: 支援不同的 Serialize 方式
  • ActiveRecord Identity Map:支援 Identity Map,相同的資料庫資料也一定會是同一個物件,可以節省資源增加一致性。不過因為行為有些改變,所以預設是關的,詳見
    API 文件
  • ActiveModel::SecurePassword,可以存密碼, 不過我覺得沒啥實用,大家都裝認證相關的 Gem 來用
  • 新的 update_column 方法,這會完全忽略 validations 和 callbacks。本來的 update_attribute 雖然會忽略 validations,但是會跑 callbacks。
  • ActionPack 相關

    • Template Inheritance: Controller 繼承也可以讓 Template 也繼承
    • force_ssl: 內建了 Rack::SSL middleware 可以限制整站必須是 SSL 存取。或是在 Controller 中用 force_ssl 這個方法限定部分 Actions 要用 SSL (之前大家是裝 ssl_requirement 這個 plugin。
    • ActionController::ParamsWrapper: 這功能讓 POST 可以直接傳 JSON 和 XML 資料並自動轉成 params hash 讓你使用,可以很方便寫出一致的 JSON/XML API 介面:吐資料和接收資料都用 JSON/XML。這功能預設是關的。

    ActionView 相關

    • form_for 的 :method 參數可以不必放 :html 裡面:也就是 form_for(@post, :html => { :method => :delete }) 變成 form_for(@post, :method => :delete)
    • 如果 form 裡面有用 file_field 檔案上傳,Rails 會自動幫 form_for 加上 :multipart => true 參數,這樣就不怕忘記啦,超棒。
    • 新增 j() helper 是 escape_javascript() 的別名
    • 新增 data 參數方便設定 HTML5 data-* 屬性:
      tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)}) 會輸出 <div data-name="Stephen" data-city-state="["Chicago","IL"]" />

    其他

    • 在 rails console 中,改成預設會顯示 SQL query log。
    • CSS Sprites: DHH 去年 RailsConf 講過要有,很抱歉這次 3.1 沒有喔!! 這張票還沒兌現。

    Rails 3.2 ?

    展望未來,我想 Rails 有兩大開發重點方向:

    支援 Rich clients 的 API 介面

    @DHH 的 37Signals 用了 backbone.js 來做 Basecamp mobile 版。而 @wycats (Rails3 架構師) 加入了 SproutCore 團隊,今年他在 RailsConf 的演講 Building Rails Apps for the Rich Client 就在研究他們如何在 Rails 上設計 API 搭配 SproutCore。

    果然,這一篇 Rails core team 成員的
    A New World of Resources 透漏了他們打算從乏人問津的 ActiveResource 下手。看來設計出一套給 Rich clients (例如 JavaScript MVC 框架) 的 API Convention 慣例,會是下一個大目標。

    Middleware 大改造

    看完 RailsConf 2011: Aaron Patterson 的演講,你會發現要做 HTTP streaming 真的很難,所有 Rack Middleware 都要重新看過,因此 @tenderlove 提出了新的 Rack 介面計畫想要改寫。另外就是他發現 Rails 2 到 Rails 3 的 RPS 效能變差的主因是太多 Middleware 造成 call stack 太深了。Rails 2.3 有 51 deep、Rails 3.0 有 60 deep,到了 3.1 達到 67 deep。這也是他想要改進的地方。增加效能、節省記憶體使用量是 Rails 3.2 的一大目標。

    Ruby Tuesday meetup #19 開放報名

    這次的 Ruby Tuesday 聚會開始報名了。 其中 Josh 是我的同事,去年的 RubyConf Taiwan 跟Ruby Tuesday 有講過一次,大家可能不陌生了。Zspencer 則是最近才新認識的朋友,他是放長假來台灣玩,專長是 JavaScript 和 Ruby,熱愛 TDD 測試和 Pair-programming。跟他第一次在 RGBA_ 聚會碰面的時候,他就教我 Game of Life 這個遊戲,然後兩個人 TDD+Pair-programming 用 Ruby 模擬這個遊戲。隨後換我教他玩 Ruby Warrior,他竟然堅持玩這遊戲也要寫測試,而且這幾天還錄了screencast XD 真是個對寫程式非常熱血的傢伙啊。anyway,當場就跟他邀約了一次演講,沒想到他這幾天連 outline 都準備好了。

    時間: 2011/5/31(Tue.)PM7~PM9:30
    地點: 台北市 theBase

    報名網址: registrano.com/events/ruby-tuesday-19

    這次試試看換新場地,感謝 evenwu 找到這家店。

    Ruby和Rails時代變遷 2005-2011

    不知不覺 AWDwR 已經出了好幾版,想到疊疊樂應該會很有趣 :p

    Agile Web Development with Rails 第一版到第四版

    Programming Ruby 1.8 和 1.9

    再配上這段話:

    “Yes there are growing pains, but I wouldn’t trade this for anything. The updates/changes keep making it better and better. Thanks.” – 出自敝社客戶

    如何建立一個沒有 Parent 的獨立 Git branch

    首先,你一定會問幹嘛這樣做。我在上回的Git 演講中有提到:在 Git,你可以建立毫不相關的分支,用來保存其他資訊,就像目錄一樣。這 Branch 的用途不會被 Merge 進開發主幹,是完全獨立的。

    實務上的一個應用,就是 Github 提供的 Github Pages 功能,只要你在專案下開一個 branch 叫做 gh-pages,那這個 branch 的內容就會變成靜態網頁。我之前的作法是先分支出來,然後再 commit 一次砍掉所有檔案。雖然結果是ok可以用啦,但是總覺得 gh-pages 這 branch 有 parent 就是意思不對勁,它是完全獨立於主幹的,不應該有 parent 資訊。

    剛突然想到這個問題可以 google 看看(Github Pages上其實也有寫 XD),還真的有:

    方法一 (source)

    因為 git branch 預設是從 HEAD 分支,所以可以這樣 Hack HEAD:

    echo ref: refs/heads/newbranch > .git/HEAD
    git rm -rf .   # 砍掉所有檔案重來
    .....   # 加新檔案
    git add .
    git commit -m 'create new branch'
    

    方法二(source)

    Git 1.7.2 之後版本有支援 –orphan 參數:

    git checkout --orphan newbranch
    git rm -rf .    # 砍掉所有檔案重來
    ...  # 加新檔案
    git add .
    git commit -m 'create new branch'
    

    方法三(source)

    git symbolic-ref HEAD refs/heads/newbranch
    rm .git/index
    git clean -fdx
    ...  # 加新檔案
    git add .
    git commit -m 'create new branch'
    

    結果就像是這樣,master 跟 newbranch 的節點完全是分開的:

    RubyConf Taiwan 2011 開跑

    終於公告出來了,時間是 2011/8/26-27(週五週六),地點是目前開源社群中最夯的中央研究院人文館會議廳(跟去年一樣的場地),感謝OSSF的協助。

    很多人問第一天是週五喔? 對,第一天週五是給初學者的 Tutorial 課程,第二天週六才是主要議程。到時候報名可以只報單獨一天。

    公告內容請詳見 Ruby Taiwan 部落格的 Call For PresentationsCall For Sponsors

    至於大家期待的國外邀請講者部分,目前已經確定了兩位:一位來自 Ruby Core Team,會來講即將在今年暑假釋出的 Ruby 1.9.3,另一位則是 Ruby 社群中非常知名的 Independent tech publisher。

    雖然 CFP 截稿日是 7/1,但是我想應該會提早六月就開放報名,敬請期待 :)

    ps. 為什麼今年的RubyConf Taiwan官網還沒有出來呢? 我們的網頁設計贊助Even給我了上面這張圖說明了他現在很忙啊 XD

    我的 Git 偏好設定

    1. 讓 Command Line 指令列顯示目前處在哪一個 Git Branch 分支,最早是在 RGBA 看到這一招,非常方便。另外我最近看到一個點子是顯示從上一次 commit 之後過了多久時間,這可以提醒你是不是該 commit 了 XD

    請修改家目錄的 ~/.bash_profile 檔案 (我是用 Bash)。

    結果如下,各位可以看到目前處在 master 分支,並且這個專案已經過了 1821 個小時沒有 commit 了…. :p

    2. 安裝 Git 的 Bash autocompletion,這樣按 tab 就會有自動完成的效果,它甚至包括 git checkout 時都可以抓到你的 branch 名稱。這裡我用 Homebrew 來安裝 bash-completion,這套件其實包括很多 autocompletion script,你可以去 /usr/local/etc/bash_completion.d 這個目錄找找看。

    brew install bash-completion
    cp /usr/local/etc/bash_completion.d/git-completion.bash ~/.git-bash-completion.sh
    

    編輯 ~/.bash_profile 加入

    [ -f ~/.git-bash-completion.sh ] && . ~/.git-bash-completion.sh
    

    3. 打開 Git 的 color 顏色設定,這樣 Git 指令的輸出結果才會加上顏色,像是 git status 等:

    git config --global color.ui true
    

    4. 設定你偏好的文字編輯器和 diff 工具

    git config --global core.editor
    git config --global merge.tool opendiff
    

    5. 最後,我個人喜歡以下的 alias:

    git config --global alias.co checkout
    git config --global alias.ci commit
    git config --global alias.st status
    git config --global alias.br branch
    

    這樣只要輸入 git st 就是 git status 了。

    FYI,以上 git 設定檔的位置在 ~/.gitconfig,你也可以直接修改這個檔案。