使用 Passenger (a.k.a mod_rails) 當做開發環境

Update(2008/6/25): 提昇 MacOS 開發爽度請裝 Pane Putting the pane back into deployment

Update(2008/5/24): 更多參考連結 28 mod_rails / Passenger Resources To Help You Deploy Rails Applications Faster

mod_rails(學名是 Passenger) 出來一段時間了,陸續開始有些使用經驗分享出來,在 production 上還蠻適合RAM有限的 VPS 環境,而這篇 Ask Your Doctor About mod_rails則介紹 mod_rails 也十分適合拿來當做 development 環境,也讓我十分心動:

  1. 厭倦每次都得 mongral_rails start 或 script/server?而且還要佔 terminal tabs。像我手上同時間好幾個案子(?!),常常要切來切去還挺麻煩的。有了 mod_rails 設定好之後,每個網站都隨時 ready 可以用。(怕 memory 浪費?mod_rails 可以經由設定 RailsPoolIdleTime, RailsMaxPoolSize 來限制 process 存在的時間跟數量)
  2. 單一 mongrel process 沒辦法平行處理 requests,當網站圖片東西比較多的時候,速度就慢了。而 mod_rails 在有額外的 request 需求時,會 new process 來支援。
  3. 有 Apache 就可以設定 SSL,只用 mongrel 沒辦法測試 HTTPS 連線。

心動了當然得馬上行動,參考了這篇 Using Passenger on OSX for Rails development,我很順利地在我的 Mac Leopard 上架了起來:

1.安裝 Passenger:

gem install passenger
passenger-install-apache2-module

2.設定 Apache,編輯 /etc/apache2/httpd.conf 或 /etc/apache2/users/ihower.conf,以下是一個範例 (前三行請參考執行 passenger-install-apache2-module 時顯示的訊息) :


LoadModule passenger_module /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.1/ext/apache2/mod_passenger.so
PassengerRoot /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.1
PassengerRuby /opt/local/bin/ruby
PassengerMaxPoolSize 3
PassengerPoolIdleTime 300
RailsEnv development

<Directory "/Users/ihower/RailsCode">
Order allow,deny
Allow from all
</Directory>

NameVirtualHost *:80

<VirtualHost *:80>
DocumentRoot "/Users/ihower/RailsCode/project1/public"
ServerName project1.local
</VirtualHost>

<VirtualHost *:80>
DocumentRoot "/Users/ihower/RailsCode/project2/public"
ServerName project2.local
</VirtualHost>

  1. 設定 /etc/hosts 指定本地端 domain:

    127.0.0.1 project1.local
    127.0.0.1 project2.local

4.打開 Mac 上的 System Preferences ➔ Sharing ➔ Web Sharing,啟動 Apache。
5.打開你的瀏覽器,輸入 project1.local, project2.local 順利的話就可以看到啦。

問: 修改了 /vendor/ 下面的東西要重新載入怎麼辦?
答:mod_rails 的用法挺有趣的,請執行:

touch tmp/restart.txt

如果要一直修改 vendor 的話(在寫plugin嗎?),可以下載 Automation with RStakeout,然後執行:

ruby rstakeout.rb "touch tmp/restart.txt" "vendor/**/*"

這樣一有更動就會reload了,cool。

Github 分散式版本控制的殺手級應用

最近常常推薦人家去玩 Github,到底有用在哪裡? 就來寫一篇廣告文吧。

GitHub 是基於 Git 這套分散式版本控制系統的 Repository hosting 應用,一開始我也沒聽過 Git ,覺得用 Subversion 好好的為什麼這些人要換。抱著嚐鮮的念頭用了之後,發現實在好玩極了。目前已經有非常多的 Rails 相關應用都已經在上面進行開發,包括Ruby on Rails coreRSpecwill_paginate pluginattachment fu_plugin等等,幾乎所有我用到的 Rails plugins 在上面都可以找的到。

到底有那些特色呢?

  1. 你可以 watch 你所關注的專案,Github 提供 private RSS 訂閱。有了這個功能,我有用到的 plugins 的進度我都可以掌握。
  2. 可以看到哪個專案最多人 watch,比較哪個比較多人用(比較多人用比較保險?)。
  3. 你可以 follow 你所關注的開發者動態(例如ihower),看看又有什麼新的好東西 :p
  4. 你可以對專案 fork 出自己的版本進行開發,甚至最後發 pull request 要求 merge。
  5. 根據 fork 我就可以看到這個專案的分支 Network 狀態。有時候可能本來的程式不好用或爛掉了,你就可以查看看有沒有人寫做 patch 改進。
  6. 漂亮的 Source code browser,並可以針對 commit 來做留言討論,甚至標明是 source code 的哪一行(請把滑鼠移到原始碼的行數旁)。
  7. 提供 tarball 下載,即使沒裝 git command 也十分方便下載。
  8. GitHub 可以直接當做 Ruby gem server
  9. 針對 Repository 可以搜尋 code, commit message, author 等
  10. Git (我的感覺)比 SVN 又快又穩,用 SVN 常常會因為檔案太多中途失敗。

Github 根本就是 Open source developer 的 social networking 啊,聽說這股浪潮已經從 Ruby/Rails 圈吹到 JavaScript 跟 Perl 了(?),這都要歸功於 Git 這套優異的分散式版本控制系統。

BTW,幫忙宣傳 Jserv 在這週二的演講:我愛 Git – 有效使用分散式版本控制系統

Ruby & Rails on Rails 進階書單

都2008年了,還看我前年列的書單讓我有點不安,只好再整理一次。這次不列”所有”了,紅了之後入門書太多。而是整理我覺得值得一念的書及PDF。

Ruby

Ruby on Rails

投影片:Practical Rails2

釋出今天在OSDC的投影片,下載PDF請按此。題目雖然定成 Practical Rails2,但主要的內容是談 RESTful Rails 實做。

有了上禮拜在 HappyDesigner3 的經驗,這次試著講慢一點,應該有穩一點。
(開始前挺緊張的,結果人一半跑到隔壁聽 Keroro 桌面,瞬間壓力減輕不少 XD)
準備的投影片到上台前有了150張,本來還擔心會不夠,結果還講不完,只好跳掉了兩個自己寫的 Rails Plugin 介紹… :p

well, 請多指教 :>

補充: 傳到 sliceshare 後,發現旁邊的相關投影片有一份 RESTful best practices也值得一看 (如果你還有興趣的話…XD)。

小探 Rails ActiveSupport

Update(2008/4/9): 這篇 RAILS RUBYISMS ADVENT也可以一看。

ActiveSupport 是 Rails 的工具箱。最近在看 Advanced Rails, O’Reilly 一書,有幾樣東西值得記上一筆:

JSON

我們有 Object#to_json,物件如 array,hash 等都可以呼叫 to_json 轉 JSON 格式,非常方便與 JavaScript 做銜接。

Blank

所有的物件都加上了 blank? 這個函式,回傳 true 如果是 1. 空字串 2. 只含空白的字串 3. false 4. nil 5. empty array [] 6. empty hash {}。所以別再寫 ( s.nil? || s.empty? ) 啦。

Class Attribute Accessors

可用宣告的方式定義 Class Attribute,如

  class Foo
     cattr_accessor :bar
     self.bar = ""
  end

這樣會定義出來的 C.bar 即 @@bar

Class Inheritable Attributes

Class Attribute 是整個類別繼承體系共用,這在我們寫 ActiveRecord 相關 plugin 時非常不適用,因為所有的 model 都繼承自 ActiveRecord,但是各自又要有不同的 Class Attributes 值。最常見的使用狀況就是 plugin 了,model A 和 model B 都 include 某個 plugin,但是這個 plugin 的設定值要不一樣。拿大家都在用的 attactment_fu 舉例:

class UploadImage < ActiveRecord::Base
  has_attachment :content_type => :image, :storage => :file_system
end

翻出 has_attachment 的 source code 你就看到這招了:

def has_attachment(options = {})
      ......
     class_inheritable_accessor :attachment_options
     self.attachment_options = options    # 這裡的 self 指的是 UploadImage
      ......
end

除了 class_inheritable_accessor(syms) ,還有 class_inheritable_array(syms) 和class_inheritable_hash(*syms) 等。

Class Attribute Accessors 的原理可以請參考 class instance variables 這篇。

Date and Time conversions

不需要每次寫 Helper 用 strftime,我們可在 environment.rb 新增自訂的 format,例如

 ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!( :foo => '%m/%d %l:%M %p')

這樣就可以對 Time 物件呼叫 to_s(:foo),內建還有 :default, :short, :long, :db 等等。

alias_method_chain

在 Rails source code 十分常見:

  alias_method_chain :target, :feature

等同於

  alias_method :target_without_feature, :target
  alias_method :target, :target_with_feature

Delegation

將 methods 傳給另一個 object

  class Account < ActiveRecord::Base
      has_one :foo
      delegate :free?, :to => :foo
  end

這樣 account.free? 就會呼叫 account.foo.free? 考慮 foo 可能 nil,我們可以多一個檢查:

  delegate :free?, :to => "something.nil? ? false : something"

甚至兩層,假設 foo 有 bar:

  delegate :free?, :to => "foo.bar"

這樣 account.free? 就會呼叫 account.foo.bar.free?

#Object#returning

讓你執行一些操作然後傳回:

 returning(User.new) do |u|
   u.name = "Foo"
 end

#Object#with_options

最常用在 routes.rb,不過其實任意物件都可以用,他會將參數自動 merge 到 method call 的 hash 參數:

 map.with_options( :controller => "people" ) do |p|
   p.root :action => "index"
   p.about :action => "about"
 end

全文搜尋 Sphinx on Rails

Update(2009/3/31): 除了 ultrasphinx 之外,還有一套 Ruby library 是 thinking sphinx 目前已經是最被推薦的 Rails 套件,我也推薦改使用 thinking sphinx,peepcode 有出它的 PDF

雖然在 Ruby/Rails 圈比較常聽到 Ferret,不過這隻雪貂的穩定度一直為人所詬病。我在 survey Rails 全文搜尋方案的時候,看到另一個有 Rails plugin 支援的開放源碼全文搜尋引擎 Sphinx,搭配的 Rails plugin 叫做 Ultrasphinx

Sphinx 的特點在於它直接存取 MySQL (或PostgreSQL),完全獨立於 Rails app。它不像 acts_as_ferretacts_as_solr 使用 rails callback 來做新資料的索引動作,而是設定 crontab 定期跑 indexer (如每半小時),大大提高了 search daemon 穩定度(反之亦然),也不太有索引資料損壞的問題(在講ferret?)。目前看到的評價也都是穩穩穩高效能,用過就不想再用 Ferret 了。Ultrasphinx 的作者也有 benchmark 數據可供佐證。

閱讀全文〈全文搜尋 Sphinx on Rails〉