Ruby Tuesday #9 開始報名

Update(2010/2/28): Ruby Tuesday #9 講題更換及 #10 開催

Ruby Tuesday 聚會辦到第九次啦,這一次很難得由 Josh Moore 帶來 JRuby on the Google App Engine,終於找到人來講 JRuby 了,我特別好奇 JRuby 跟我們一般用的 MRI 到底用起來有什麼差別的地方。

另一場演講則是由我帶來 Rails Best Performance and Security Practices,這個題目從我在準備 Rails Best Practices 就肖想了,當時的重點著重在程式怎樣寫的容易擴充跟維護,所以有一些效能跟安全性的最佳實務只好忍痛割愛。這次趁與 OSSF 合作,就來準備這個題目。

時間: 2010/3/9(週二)晚上七點到九點半。

地點: 台北市 果子咖啡

報名網頁: registrano.com/events/ruby-tuesday-9

使用 git rebase 避免無謂的 merge

關於 Git 可以參考我的 Git 版本控制 課程資料

可以進一步參考 Git rebase 和 merge 合併操作示範錄影

git pull 預設的行為是將遠端的 repo. 與本地的 repo. 合併,這也是 DVCS 的初衷,將兩個 branch 合併。但是,很多時候會發生以下這種情形:

這是因為,我們團隊的開發模式是本地的 branch 和遠端的 branch 會同步地非常頻繁(通常就是同名稱的 branch,例如 master),這兩個 branch 幾乎是完全同步。這時候就會發現這些 merge 動作其實沒有必要,會造成線圖無謂的複雜。這時候,會推薦使用以下這個指令:

 git pull --rebase

加上 rebase 的意思是,會先 1.把本地 repo. 從上次 pull 之後的變更暫存起來 2. 回復到上次 pull 時的情況 3. 套用遠端的變更 4. 最後再套用剛暫存下來的本地變更。詳細說明可以參考 pull with rebase

畫圖說明一下好了:

假設合併前是這樣:

      D---E master
     /
A---B---C---F origin/master

使用 merge 合併後:

      D--------E  
     /          \
A---B---C---F----G   master, origin/master

如果是 rebase 的方式,就不會有 G 合併點:

A---B---C---F---D'---E'   master, origin/master

注意到,其中 D’, E’ 的 commit SHA 序號跟本來 D, E 是不同的,因為算是砍掉重新 commit 了。

你會問說,有 conflict 怎麼辦? rebase 跟 merge 類似,出現 conflict 一會暫停 rebase 動作,需要你手動修復後,然後才可以繼續動作。這也是 rebase 比 merge 複雜一點的地方:merge 如果發生 conflict,你只需要解決衝突一次,然後 commit 出去就完成了。而 rebase 的 conflict 可能會發生在上述步驟 4 的每一次重新套用上,所以可能需要解決衝突好幾次 (rebase 時所謂的解決衝突,其實是直接修改你之前的變更內容,所以上圖中變成 D’ 跟 E’ )。

所以到底何時該用 merge? 何時可以 rebase? 你可能心理也有答案了,如果你修改比較多,預期會有較多的 conflict,建議用 merge (不過,如果是多次大範圍的主題式修改,那是不是應該一開始就多開一個 branch 來做呢?)。如果修改範圍較小,不太預期有 conflict,則建議可以加上 rebase 參數。

如果想要把 rebase 當做 git pull 的預設值,可以在專案的 .git/config 加上


[branch "master"]
  remote = origin
  merge = refs/heads/master
  rebase = true

也可以直接加到 ~/.gitconfig 讓所有的 tracked branches 都自動套用這個設定:


[branch]  
  autosetuprebase = always

RubyConf Taiwan 2010 開始報名

疑?怎麼今年的 OSDC.TW 大會沒有任何 Ruby 場次? 這是因為今年我們 Ruby Taiwan 社群決定與 OSDC.TW 並行獨立出來一整天的 Ruby 議程啦,詳細內容及報名請前往 RubyConf Taiwan 網頁。

台灣的 Ruby 社群很小,但是我們的眼界跟志向不低。這是我們第一次舉辦國際性的 Ruby 程式語言研討會,講者群中包含了來自美國、日本以及大陸的朋友,相信可以帶給我們不同的視野及經驗。一天的議程安排地非常緊湊(也許明年可以來辦兩天了),真是非常興奮又期待。

身為活動主辦人,我要特別感謝 OSDC.TW 與我們分享了會場、EvenDesign 贊助了專業的網頁設計,以及 Handlino 贊助了網域名稱費用和提供 Registrano 報名網站。如果貴單位有意願贊助這項活動,歡迎與我們聯繫([email protected])。

Ruby on Rails 由淺入深課程(2/27,28) 開放報名

又要開課啦,由 中央研究院 資訊創新研究中心自由軟體鑄造場主辦的自由軟體技術分享工作坊—Ruby On Rails由淺入深課程。這是兩整天共 12hr 的上機實作課程,名額有限、完全免費。

活動名稱:自由軟體技術分享工作坊—Ruby On Rails由淺入深
活動時間:2010.02.27(六)/ 2010.02.28(日)
活動講者:ihower
報名首頁:whoswho.openfoundry.org/workshop.html
活動地點:台北市復興北路99號2樓 (恆逸教育訓練中心)

Rails3 和 Rails2 的 rails 指令如何都能運作?

裝了 Rails3 beta 之後啊,那個 rails 新建專案的指令就變成產生 Rails3 了,那要怎麼產生本來的 Rails2 版本呢? 今天 Ruby Tuesday 聚會有人問了我這個問題。

整理 Rails3 資料的時候就有看到解法,回答如下:

首先,如果還沒裝 Rails3,請先將本來 Rails2 版本的 rails 指令複製一份成 rails2 (可以打 which rails 可以找到位置,這個檔案跟 gems/rails-2.3.5/bin/rails 不一樣哩),然後將裡面的 version = “>= 0” 改成 version = “~> 2.0” 即可。之後執行 rails2 project_name 就可以產生 Rails2 版本的專案了。這個 rails2 的檔案長得如下(第一行的 ruby 位置你的可能跟我不一樣):


#!/usr/local/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'rails' is installed as part of a gem, and
# this file is here to facilitate running it.
#
 
require 'rubygems'
 
version = "~> 2.0"
 
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
  version = $1
  ARGV.shift
end
 
gem 'rails', version
load Gem.bin_path('rails', 'rails', version)

如果你已經安裝了 Rails3,那 Rails3 的這個檔案跟 Rails2 的差異只在最後兩行而已。

Rails3 Beta 發佈: 重點導覽

Update(2010/2/22): The Rails 3 Upgrade Handbook 可以買來看。

從 Merb 和 Rails 決定合併開始,過了一年多的努力終於發佈 Beta 版啦。Rails3 最重要的人物就是總架構師 Yehuda Katz 了,整個把 Rails core 翻了好幾翻,徹底改頭換面。

Why? 我是這麼想的,DHH 一開始開發 Rails 的時候,Ruby 社群還不像現在這麼發達,所以很多事情必須自己造(連 prototype 都是為了 Rails 而造的),為了達到非常容易設定跟快速開發的理想,得包山包海什麼功能都要做,再加上有限的資源,造成了 Rails core 其實綁得很緊,基本上就是一整包給你。要修改擴充它,常常就必須 monkeypatch 一下。另一方面,對怎樣的 Ruby 程式是好程式,一開始也沒有這麼多人想清楚,例如 Rails core 充滿了 alias_method_chain,這件事情現在也被認為是比較不好的寫法。

Rails3 的時代不同了,Ruby 社群起來了。我們有標準的 Rack 介面、我們有不同的ORM甚至是 NoSQL 的儲存庫、我們有不同 JS Libary、我們有不同測試方式 RSpec、我們也有許多現成不需要自己造的新函式庫。Rails3 基本上就是這麼一個接近改掉重寫的版本,但是以重構的方式達成了這個兼容並蓄的目標:將 API 重新釐清、徹底模組化、低耦合度元件、大幅提昇效能等。具體來說,有幾個成果:

使用 Ruby 1.8.7 或 Ruby 1.9.2

1.9 的時代終於要來臨了 :) 可以複習一下我去年演講的投影片

Dependencies 管理

本來的 config.gem 換成新的 Bundler 來管理所有用到的函式庫,使用新的 Gemfiles 格式,本來的 config.gem sucks 問題多功能有限。現在,我們真的做到可以完全不依靠系統 gems。可以參考這篇 Bundle me some RailsUsing Bundler in Real Life 示範 Bundle 的用法

新的 Routes

由於全面導入 Rack 的關係,現在的 Route 其實也是一個 Rack middleware,實作上就是 rack-mount。新的 Route 第一眼看到就是 API 的改變了,可以參考這篇 Revamped Routes in Rails 3The Lowdown on Routes in Rails 3,不過這其實不是最重要的地方,最厲害的地方是,它參數 :to 接的端點其實是 rack 端點,而 main#home 是 MainController.action(:home) 的簡寫( 是的!! Rails3 中每個 Controller actions 全都是一個標準的 Rack app!! 超酷!!),可以看看 Yehuda 的實作說明。既然是 Rack 端點,我們就可以給它接其他 Rack app,例如 Sinatra,這一篇就示範了怎麼接 Rails 3 Routing with Rack,真是超級簡單啊。我們可以預期,會有更多有趣的 Rack middlewares 可以與 Rails 結合。

另外,我們也可以直接在 Routes 層直接辦到 redirect 和 render template,可以看看 Yehuda 的實作說明:Generic Actions in Rails 3,基本上就是簡單的 Rack middleware。

新的 Active Model

為了達到與不同 ORM 銜接的目標,Rails3 的 ActiveModel 將本來的 ActiveRecord 的個別功能抽出來成為 Module,例如 callbacks, validations, serialization, observing, dirty tracking 等。任何 Class 只要符合 ActiveModel 定義的幾個 API,再加上 include 你需要的 Module,就可以與 Rails3 接在一起了。請參閱 ActiveModel: Make Any Ruby Object Feel Like ActiveRecord

其中 Validation 有新的 API,請參閱 validates :rails_3, :awesome => true

ActiveRecord

那 ActiveRecord 本身呢? 引入了 ARel 這套 SQL 產生工具(why Arel?),大幅採用 “method chain” 的串接用法,讓每個操作都變成了 scope。

ActiveRecord 因此也有了新的 API: Active Record Query Interface 3.0

ActionController

Responder 帶來了 respond_with,可以簡化 controller 的寫法,用法參考 Cleaner RESTful Controllers w/ respond_withDefault RESTful RenderingThree reasons to love ActionController::Responder 這幾篇。這工具非常有趣,我之前甚至寫了一個 plugin respond_methods 來讓 Rails 2.x 支援這個功能。

另外,新的 Render 實作可以讓你輕易擴展,這一篇 Render Options in Rails 3 示範了怎麼做出你自己的 render :pdf。

ActionView

幾個大的改變:

1. 採用 Erubis 實作
2. 預設 XSS protection 打開,再也不用忘記加上 h 逸出了。請參考 SafeBuffers and Rails 3.0 有更多細節
3. 將所有 JavaScript helpers 改成 unobtrusive。你會發現 Rails3 的 public/javascripts 多了一個 rails.js,這就是一個 JS driver,預設是接 prototype.js,要換成 jQuery 非常簡單,只要用 jQuery 版本的 rails.js 就可以了。因此本來的一些 Ajax Helper 就被移除了,有需要的話可以在 prototype_legacy_helper plugin 找回來。
4. Helpers 預設輸出格式是 HTML 5。

說到 HTML5,我另外推薦這份閱讀材料 Dive into HTML5 以及 HTML 5 Demos and Examples

ActionMailer

首先底層換成 Mail 這套工具了,可以參考這篇介紹。接著,受益於 Controller 的重構成果,新的 ActionMailer 終於和 Controller 繼承自同一個 AbstractController,讓 ActionMailer 的功能增加不少,也大大的 DRY 了。

新的 API 請參考 New ActionMailer API in Rails 3.0

最後它的位置改放在 app/mailers 了,放在 app/models 下實在讓人搞混啊。

ActiveSupport

之前的 ActiveSupport 有個討厭的地方是,如果你只想要用到其中的幾個功能,很不容易搞懂到底要 require 哪些東西,最後只好通通載入以求保險。新的 Rails3 把這件事情弄清楚了,你可以只載入你要的部分。

Rails Application object

為了讓一個 Process 可以跑多個 Rails app,Rails3 使用了一個 Rails Application 物件來表示一整個 Application 的所有設定,因此本來的 config/environment.rb 的功能,幾乎都搬到 config/application.rb 了。另外,Rack 的標準 config.ru 檔案也被加到了根目錄,因此要特別注意到你的 Application 名稱,這會是跟其他 Application 互動時使用的名稱,預設是目錄的名字。

新的 Rails Module

幾個常數被拿掉了,RAILS_ROOT 要改用 Rails.root、RAILS_ENV 要改用 Rails.env、RAILS_DEFAULT_LOGGER 要改用 Rails.logger 等,詳細請參閱這篇 The Rails Module (in Rails 3)。改成物件的好處是,我們就不需要做字串操作這種事情了。

新的 rails 指令

本來的 script/* 指令全部拿掉了,都改成用 rails。例如 script/console 變成 rails console (可以簡寫成 rails c)、script/generate 變成 rails generate (可以簡寫成 rails g)、script/server 變成 rails server(可以簡寫成 rails s)。使用 rails –help 可以看到完整說明。

推薦閱讀

Rails3 的閱讀資料非常多,官方的 Rails 3.0: Release Notes 是必讀。如果你從升級的方向切入,可以使用官方的升級 Plugin rails-upgrade is now an official plugin,它可以幫助你 1. 檢查需要升級的地方 2. 產生 Gemfile 3. 產生新的 routes.rb。請搭配這篇 The Path to Rails 3: Approaching the upgrade 服用。不過,嗯,現在還是不要在 Production 環境上升級比較好,畢竟很多 Plugin 還沒跟上來哩 (可以看看 Is Your Plugin Ready For Rails 3?Rails Wiki 有整理哪些 Plugins OK 了)。

如果是從重新開始會容易得多,可以看 The Path to Rails 3: Greenfielding new apps with the Rails 3 beta 這篇。十分建議你有空的話,現在就可以開始玩玩看了。

如果想多了解 Rails 的架構,有幾篇文章可以看看:

最後,如果你還想找更多,英文的懶人包有:Rails 3 ResourcesRails 3.0 Beta: 36 Links and Resources To Get You GoingRails 3 Reading MaterialOn the way to Rails 3 – a link list