<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>{&#124;ihower.tw&#124; blog } &#187; Rails</title>
	<atom:link href="http://ihower.tw/blog/archives/category/rails/feed" rel="self" type="application/rss+xml" />
	<link>http://ihower.tw/blog</link>
	<description>Ruby, Ruby on Rails, Mac and Agile development</description>
	<lastBuildDate>Tue, 27 Jul 2010 06:48:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Enterprise Rails: 資料庫篇</title>
		<link>http://ihower.tw/blog/archives/3337</link>
		<comments>http://ihower.tw/blog/archives/3337#comments</comments>
		<pubDate>Wed, 07 Jul 2010 14:07:48 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=3337</guid>
		<description><![CDATA[
稿子是 2009 年底寫的，本來想一口氣連 SOA 的部份一起整理 (對 SOA 有興趣的話，可以看我之前的投影片 91 頁 ~ 119 頁)，不過一直拖到現在。雖然內容還是有點些雜亂，而且現在流行 NoSQL (?)，不過還是就貼出來吧。
這本 2009 年底的書，趁著轉職的空檔終於一口氣讀完了。有些重要的背景知識，如果你一直追所謂的最新技術，反而是學不到。這本書其實講 Rails 不多，前一大半都是在講 RDBMS 關聯式資料庫，後半則是 SOA 架構。
像 RDBMS 裡面的 referential integrity、composite key、DB View、triggers、materialized View 這些東西，因為身為 MySQL 使用者很少用到、Rails 也沒有內建支援，實際寫 code 好像也都在 application layer 應用層處理掉了，所以到底要幹嘛用的呢? 他們被發明一定有原因吧? 是在什麼情境上使用呢?
第四章 Database As a Fortress
作者非常強調資料庫的重要，一家企業最重要的資產是資料，而不是員工 (資料不見就全完了，員工沒了再找就有了)。Framework 會變、程式會有 bug、可能也不會只有 Rails 會去存取 DB (所以只用 ActiveRecord Validation 並不可靠)，總之只有你的 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://oreilly.com/catalog/9780596515201"><img src="http://covers.oreilly.com/images/9780596515201/cat.gif"></a></p>
<p>稿子是 2009 年底寫的，本來想一口氣連 SOA 的部份一起整理 (對 SOA 有興趣的話，可以看我之前的<a href="http://www.slideshare.net/ihower/distributed-ruby-and-rails">投影片 91 頁 ~ 119 頁</a>)，不過一直拖到現在。雖然內容還是有點些雜亂，而且現在流行 NoSQL (?)，不過還是就貼出來吧。</p>
<p>這本 2009 年底的書，趁著轉職的空檔終於一口氣讀完了。有些重要的背景知識，如果你一直追所謂的最新技術，反而是學不到。這本書其實講 Rails 不多，前一大半都是在講 RDBMS 關聯式資料庫，後半則是 SOA 架構。</p>
<p>像 RDBMS 裡面的 referential integrity、composite key、DB View、triggers、materialized View 這些東西，因為身為 MySQL 使用者很少用到、Rails 也沒有內建支援，實際寫 code 好像也都在 application layer 應用層處理掉了，所以到底要幹嘛用的呢? 他們被發明一定有原因吧? 是在什麼情境上使用呢?</p>
<h3>第四章 Database As a Fortress</h3>
<p>作者非常強調資料庫的重要，一家企業最重要的資產是資料，而不是員工 (資料不見就全完了，員工沒了再找就有了)。Framework 會變、程式會有 bug、可能也不會只有 Rails 會去存取 DB (所以只用 ActiveRecord Validation 並不可靠)，總之只有你的 RDBMS 可以保障資料的正確性，data integrity 長存。</p>
<p>PostgreSQL 也比 MySQL 適合企業應用，因為很多 SQL 標準 MySQL 並不支援 (很多直到 5.0 後才支援)。PostgreSQL 會輸掉市佔率的原因是 1. MySQL 背後有一家商業公司支持 2. PostgreSQL 有很長一段時間不像 MySQL 有提供 Windows 安裝包 (話說這本書對 MySQL 其實還蠻揶揄的)。</p>
<p>作者也不建議使用 migration，因為它沒有支援所有的 DDL (Data Definition Language)。反正只有跑一次，不像 DML (Data Manipulation Language) 會一直用，用 ORM 比較方便。</p>
<p>作者持續強調 referential integrity 對企業層級的上線應用程式非常重要。會說不重要的，一定是該死的 MySQL 使用者(died-hand MySQL users)，千萬別因為你的工具(i.e. MySQL, Rails)沒有這個功能，就說不重要。</p>
<p>隨著資料越來越多，你的老闆會想要知道一些數據分析報表，這裡作者點出一個重要的議題：你的報表會害了你的網站!! 你越常去產生你的報表，你的網站就會越來越慢。&#8221;Report are killing your site!!&#8221; 為什麼呢? 因為去 DB 撈大量的資料做報表，是非常龐大複雜的 SQL 操作，你的 DB 的效能會被拖慢，整個網站的效能就跟著 down 下來。該怎麼解呢? 撈 report 的 queries 不要對 production database 做就沒事了吧?</p>
<p>這裡作者又對 MySQL users 揶揄了：因為大多數的 MySQL users 第一個想到的方案就是使用 master/slave 來解決，也就是讓 query report 對 slave DB 做，但是即時如此不會影響到 production 運作，也沒辦法解決 query 查詢很慢的問題。</p>
<p>這裡觀念上要區分的是 OLTP (Online Transaction Processing) 和 OLAP (Online Analytical Processing 這兩種類型的 query，前者是一般的讀/寫/更新，這種是會讓使用者可以馬上等結果，大部分的前台網站就是屬於這種。後者則是一個 query 就須需要收集上百萬的資料去分析，例如：有多少客戶買了產品A，又買了產品 B，依照地點跟時間。</p>
<p>因為 OLTP 和 OLAP 是如此不同，沒道理 database 的設計也相同。OLAP 要快，就必須使用 denormalized 非正規化的方式來存放資料。但是將正規化資料和逆正規化資料混雜在同一個 DB，則非常容易造成資料的混亂不同步，寫出 buggy 有臭虫的程式。</p>
<p>要解決這個問題的領域是使用獨立的 data warehouse 存放 denormalized 的資料。(書就到此打住了，作者推薦了 <a href="http://www.amazon.com/Data-Warehouse-Toolkit-Complete-Dimensional/dp/0471200247">The Data Warehouse Toolkit: The Complete Guide to dimensional Modeling</a> by Ralph Kimball 一書)</p>
<h3>第五章 Building a Solid Data Model</h3>
<p>Data layer 層級的 constraint 才保證一定正確，因為應用層的 Model validation 可以跳過，放在 code 裡也容易被改掉。作者也示範了這兩者都可以寫單元測試。</p>
<p>referial constraint 如果只用 Model 做，destroy 時就會失效。而 Model 要做 referial constraint 只能用 has_many :depentent 但是如果誤用了 :delete 就 orz 了。因此最保證的作法還是 data layer 做。</p>
<p>資料庫記得加 index 在 1. foreign key 2. 任何有 SQL where 條件的地方</p>
<h3>第六章 Refactoring to Third Normal Form</h3>
<p>3NF (三階正規化) 能做到 DB 資料不重複：只要不是 primary key、不是 foreign key、不是 intrinsic data(eg. name)、不是 measured value (例如 time, temperature)，而是一個  literally bound data，都應該正規化出來新建一個 table。不先做，後來要加會十分痛苦，尤其在一個已經有資料的 production db 上。</p>
<p>範例中的有很多 table 都有相同的地址欄位定義：Postgres 支援 multipie inheritance，可以處理重複的 DDL，再搭配上 Rails 可用 plugin mixin 處理重複的 code。</p>
<p>這裡留下一個第八章才回答的問題，只有一個 primary key 沒辦法一次撈出 has_many 的 has_many 資料。多保留一個 foreign key 又可能造成 direct 和 in-direct 的資料不一定一致。</p>
<h3>第七章 Domain Data</h3>
<p>Domain data (指網站預先就有的必要初始資料，又叫做 seed data) 也應該使用 table 存，因為 1. 保持 referential integrity 2. 維護 3ND 跟擴充彈性。實作上則可以做成常數形式。</p>
<p>strategy patterns with domain tables 這招示範了將 Order PAYMENT_TYPE 變成 domain tables 來做，除了變成 constant object，情境是如果不同 payment_type 會有不同的 validation。首先變成 constant 後，可以順利將 validation code 都從 order 搬走。而再進一步 rails single table inheritance 和 template method 將 validation 分散到個別的 domain model。總之，作者將 domain data 的彈性做了非常好的示範。</p>
<p>雖然正規化會導致大量的 table 和 model，但是也因為如此每個都很小非常容易測試，bugs 也就容易集中在小區域容易找到。</p>
<h3>第八章 Composite Keys and Domain Key/Normal Form</h3>
<p>這章討論 composite key 的優缺，以及如何使用。</p>
<p>ID column 系統的優點 1. Rails 內建 2. 簡單，除了 primary key 之外皆可修改，物件的 primary key 一定不變 3. 提供與真實資料的間接性，因此也不需有修改 primary key 的機會。 4. unique key 好做</p>
<p>composite key 的優點就沒這麼顯而易見，也不一定用的到。他的用途在於提供一種特別的 data integrity。table 中不一定可以發現有 natural composite key, 但是如果有而你忽略他，可能會有大問題。這個情境就是：</p>
<p>只有一個 primary key 沒辦法一次撈出 has_many 的 has_many 資料，如果只是加上一個 reference key, 可能導致 refential integrity hole. 這時 composite key 才是唯一解決之道。</p>
<p>DFNF 比 3NF 更近一步保證 referential integrity 在複雜的 relationship 中。不能因為工具沒有，就覺得不重要。因為 Rails 沒有內建，導致很多人不知道 DK/NF or natural keys 等這些已經發展成熟的資料庫基礎理論，在設計 schema design 上而有很大的缺陷。</p>
<p>先來檢討 single column ID 是否應該用 Rails 內建的數字，首先找有沒有別的 unique column，再來覺得它是否不會 或 不常變更，特別是連編輯介面都沒有的 domain data 特別符合這個條件，如果是，則可以用 set_primary_key 換掉，移除不必要重複 id column。不過，如果不是 domain data, 我們就必須產生這個 primary key，用法是寫在 before_create 裡，另外要注意還是使用 self.id。一個額外的好處是，這些可能被當做 foreign_key 的 nature key，也是有用的資訊，不像本來的數字 id 一定還要去本來的 table 查。</p>
<p>這裡我有個疑問是 <a href="http://stackoverflow.com/questions/332300/is-there-a-real-performance-difference-between-int-and-varchar-primary-keys">Is there a REAL performance difference between INT and VARCHAR primary keys?</a> ，在我碰到的例子是，很多人擔心非 integer 當 key 會影響效能 :/ (題外話，很多人愛用 type code，但都被我建議改成 string constant ) 但是我想這差距的微乎其微，尤其在你沒有上百萬的資料列。重點還是，你選的 nature key 不需要有被修改的可能 :></p>
<p>Rails 要支援 composite keys 有兩個方法，一個是使用 Dr. Nic Williams 的 plugin，一個是本書作者的 Rails-DK/NF hybrid 法：</p>
<p>具體的作法是，保留 ID column 欄位，但是 DB 還是加上 composite key 的 foreign key referential integrity 限制。好處在 Rails 裡面不方便改 primary key, 當有修改的需求時，使用 hybird 法就不錯簡單(不需要裝plugin)。但是回過頭想，如果你需要修改 nature key，可以先想想是不是最好的作法應該是刪掉舊的，插入新的。</p>
<p>一個小技巧是附寫掉本來的 writor，這樣就不需要手動設定 composite key 的值了。如果要改已經被 reference constraint 限制的 composite keys 怎麼辦? 直接改會爆，這時候需要使用 deferrable constraints 的機制和  transaction。</p>
<p>不過 hybrid 法的缺點是 1. 因為維護兩套 index key 的關係, 新增修改刪除的 index cost 比較高。 2. 需要多寫上述的 code 才能省掉手動設計的麻煩。</p>
<p>書沒寫哪個最好，看起來是如果非得有修改 nature key 的需求才只用 hybrid 法。</p>
<h3>第九章 Guaranteeing Complex Relationships with Triggers</h3>
<p>stored procedure 和 triggers<br />
使用 PL/pgSQL 做例子。</p>
<h3>第十章 Multiple Table Inheritance</h3>
<p>Rails 的 polymorphic associations 功能讓你可以定義兩個 table 的關係，不需要事前知道是哪一個 table。</p>
<p>不過，polymorphic associations 違反了 referential integrity !! 原因很簡單，既然不知道 _id 會指到哪個 table，自然也就沒辦法在 DB layer 加上 foreign key constraint</p>
<p>什麼是多型? </p>
<p>要達成多型的方式，實作上要考慮的是 STI 或 MTI：前者 Rails 有內建，後者 Rails 有用了 polymorphic 方式來達成 XOR relationships，也算是一種簡易的 MTI。</p>
<p>這本書用了 logical 和 physical models 來分別描述概念上和實際上的切法</p>
<p>STI 適用於 subclass 共用很多 data。如果共用的不多，除了浪費 table, model 也會被 getter 和 setter 污染。另外因為 class name 寫在 table 了，如果要修改 class name 會很麻煩。</p>
<p>這裡提的 MTI 作法是，還是為了要用到的 foreign key 開欄位，並且也為每個關係加上 belongs_to，但是允許 null 值，因為要做 XOR on columns: 要用 boolean 做 XOR，兩個還好做，超過三個就複雜了。這裡的作法很聰明，轉成數字再相加，只要檢查是不是等於 1，用這樣的方法做 database constrant check。</p>
<p>都加了 belongs_to，要怎麼做到多型。這裡作者使用了 reflection 和 inheritance relationship 的技巧，在 parent object 上實作了 getter 和 setter method，厲害。我們也可以實作一個 Factory method 在 parent 上，來建構適合的 sub-class。</p>
<h3>第11章 View-Backed Models</h3>
<p>有些複雜的 join 和 conditions 單靠 active record 寫不出來(畢竟簡單好用的東西，畢竟是犧牲一些不常使用的功能)，而必須寫一些很醜的 SQL 混雜 active record，但是這樣就失去使用 active record 的意義(與DB-independent)。如果要漂亮，只能先盡可能先撈出來，然後再從 application layer 層過濾資料，但是這樣又失去效能，畢竟撈資料是 DB 的專長。</p>
<p>解法是 view-backed model，materialized view。</p>
<p>database view 有兩個定義 1. named subquery 2. a table that is defined by an algorithm<br />
後者的實作是，我們先用 SQL 定義 DB view，然後就可以用 ActiveRecord 代表那個 view/table，更 cool 的是，還可以加上 association!! 當然，這是 read-only 的，記得不要加 destroy。</p>
<p>subquery 的定義也表示，你不能對 view/ view-backed models 操作 insert/update/delete/reference/constraint/index。<br />
references 也不需要，如果你要 reference，就表示你應該加到 view 裡，constraint 也是。</p>
<p>indexing 也無，畢竟是 just-in-time 撈出來的資料。但是本來的 index 欄位當然還是有作用。別氣餒，畢竟本來使用 View 的目的不是效能，而是為了讓 AR 更簡潔清楚。如果真的需要效能，下一章的 materialized view。</p>
<h3>第12章 Materialized Views</h3>
<p>materialized view 就是 cached 的 view。既然是 cache，就一樣有 cache 的議題: 資料的更新，何時由誰 expire?</p>
<p>materialized view 是 cache-complete copy of view, 也是全部都有留資料，不像 memcached 會把不常用或超過記憶體的資料移除。</p>
<p>幾個重點: 1. materialized view 既然是實體的 table，也就可以加 index 2. 要加上 refresh function 當偵測到 base table 有修改 3. 或是 invalidation function 如果不想馬上更新 4. 在 base table 加上 triggers 以偵測修改 5. auxiliart view, reconciler view 隱藏實作細節</p>
<p>不過看完還是覺得使用 materialized view 真是挺難的!! XD</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/3337/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Rails3: 新的 Metal 機制</title>
		<link>http://ihower.tw/blog/archives/4561</link>
		<comments>http://ihower.tw/blog/archives/4561#comments</comments>
		<pubDate>Tue, 08 Jun 2010 15:32:51 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=4561</guid>
		<description><![CDATA[新的 Rails3 Controller 重構後，變成 ActionController::Base < ActionController::Metal < AbstractController 的繼承體系。除了 ActionMailer 繼承自 AbstractController，讓 API 與 Controller 一致之外，新的 ActionController::Metal 更是充滿玩味。
故事可以從上個禮拜，Yehuda 把 Rails 2 的 Metal 移除了(commit)，根據 commit 的說明，Rails 2 的 Metal 在 Rails 3 裡面，可以用 1. 放在 Route 之前的 Rack middleware 或 2. 放在 Route 之後的一個 Rack endpoint，而這個 Rack endpoint，除了自己實作 Rack app，我們也可以用 ActionController::Metal 來實作出自己的客製化 Controller。
Rails2 發明 [...]]]></description>
			<content:encoded><![CDATA[<p>新的 Rails3 Controller 重構後，變成 ActionController::Base < ActionController::Metal < AbstractController 的繼承體系。除了 ActionMailer 繼承自 AbstractController，讓 API 與 Controller 一致之外，新的 <a href="http://www.engineyard.com/blog/2010/rails-and-merb-merge-plugin-api-part-3-of-6/">ActionController::Metal</a> 更是充滿玩味。</p>
<p>故事可以從上個禮拜，Yehuda 把 <a href="http://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal">Rails 2 的 Metal</a> 移除了(<a href="http://github.com/rails/rails/commit/45e60283e733a535d68d499aa20e095c905f43b0">commit</a>)，根據 commit 的說明，Rails 2 的 Metal 在 Rails 3 裡面，可以用 1. 放在 Route 之前的 <a href="http://asciicasts.com/episodes/151-rack-middleware">Rack middleware</a> 或 2. 放在 Route 之後的一個 Rack endpoint，而這個 Rack endpoint，除了自己實作 Rack app，我們也可以用 ActionController::Metal 來實作出自己的客製化 Controller。</p>
<p>Rails2 發明 Metal 原因是，有些事情不需要完整的 Controller 功能，希望能夠越快越好，例如 XML/JSON API 等。而 Rails2 的 Metal 雖然非常快，但是沒什麼彈性，完全不能使用 Controller 的功能，例如用 Layout, Template, Sessions 等，基本上就跟單純的 Rack middleware 沒什麼兩樣。但是在 Rails3 中，可以透過自繼承 ActionController::Metal 做出白紙般的客製 Controller，可以有非常快的速度，如果有需要用到 Controller 的功能，也可以任意選擇組合加入，十分彈性。</p>
<p>例如，我們來實作一個超級精簡的 Static Controller：</p>
<pre>
<code>
# lib/static_controller.rb
class StaticController < ActionController::Metal
  include ActionController::Rendering

  append_view_path "#{Rails.root}/app/views"

  def about
    render "about"
  end
end

# config/route.rb
match '/about', :to => "static#about", :as => :about
</code>
</pre>
<p>這個範例有接近於 Metal 的速度，並加入了 Controller 的 Template 功能 (你可以參考 ActionController::Base 這是擁有全部功能的版本)。其中 &#8220;static#about&#8221; 是 StaticController 的 about action 縮寫，而在 Rails3 中，controller action 也都是一個 Rack app。</p>
<p>除了我的這個簡單範例，在 <a href="http://www.railsdispatch.com/posts/rails-routing">The Powerful New Rails Router</a> 和 <a href="http://www.railsdispatch.com/posts/upgrading-a-rails-2-app-to-rails-3">Upgrading a Rails 2 App to Rails 3</a> 的影片中，也有分別舉例。</p>
<p>總而言之，如果你在 Rails3 中不需要全部的 Controller 的功能，想要盡量拉高效能，有幾種推薦作法：</p>
<p>* 寫成 Rack Middleware，然後在 config/application.rb 中插入 config.middleware.use YourMiddleWare<br />
* 寫成 Rack App，在 config.route.rb 中將某個對應的網址指到這個 Rack App<br />
* 繼承自 ActionController::Metal 實作一個 Controller，其中的 action 也是一個 Rack App</p>
<p>其中的差異就在於後兩者會在 Rails Route 之後（好處是統一由 route.rb 管理 URL 路徑），如果繼承自 ActionController::Metal 可以有彈性獲得更多 Controller 功能。原則上，我想我會推薦 ActionController::Metal，寫起來最為簡單，一致性跟維護性較高。</p>
<p>另外，還有個小玩意， <a href="http://www.engineyard.com/blog/2009/rails-and-merb-merge-the-anniversary-part-1-of-6/">ActionController::Middleware</a> 是 Controller 層級的 Rack Middleware，讓你可以在放入到某個特定 Controller 之中(也就是只有該 Controller 使用這個 Middleware)。不過呢，這個功能我到現在還沒看到任何實用的例子就是了。 </p>
<p>最後，Yehuda 提供了一個 <a href="http://gist.github.com/426004">參考數據</a>：</p>
<pre>
<code>
fast: through middleware inserted at 0
slwr: through middleware inserted via @use@
rotr: through endpoint sent via the router
bare: through ActionController::Metal with self.response_body
cntr: through ActionController::Base with self.response_body
text: through ActionController::Base with render :text
tmpl: through ActionController::Base with simple render :template
layt: through ActionController::Base with render :template with layout

         real     rps
fast   0.004271   2900 Rack 極限
slwr   0.067029   2200 使用 config.middleware.use YourMiddleware
rotr   0.088085   2000 經過 Rails Route 之後
bare   0.103868   1900 使用 ActionController::Metal 的最快速度
cntr   0.355898   1070 使用 ActionController::Base 的最快速度
text   0.557127    825 使用 ActionController::Base 加上 render :text
tmpl   0.639581    765 使用 ActionController::Base 加上 render :template
layt   1.678789    375 使用 ActionController::Base 加上 Template 跟 Layout
</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/4561/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bundler: Rails3 用來管理 Gem dependencies 的神器</title>
		<link>http://ihower.tw/blog/archives/4464</link>
		<comments>http://ihower.tw/blog/archives/4464#comments</comments>
		<pubDate>Tue, 01 Jun 2010 10:33:14 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=4464</guid>
		<description><![CDATA[Update(2010/7/27): Bundle 1.0.0 之後不需要 bundle lock 了，只要 bundle install 就會自動 lock。

Bundler 是一套為了 Rails3 所打造的全新 Gem dependencies 管理工具：一套基於 Rubygems 的更高階套件管理工具，適合讓 Application 管理多套 Gems 依存關係的複雜情境。而你在 Rails3 中 (Bundler 不只用在 Rails3，其他例如 Sinatra 或是 Rails2 也都可以使用) 要使用的 Gems，也都必須宣告在它的 Gemfile 裡，沒寫在裡面的話，就算手動 require 也找不到。這跟已往你可以直接 require 任意  rubygems 不同，在使用 Bundler 的環境中，要 require 什麼 rubygems 必須透過 Gemfile 管理。
Gemfile 的寫法大致如下：


  # 第二個參數可以指定版本
 [...]]]></description>
			<content:encoded><![CDATA[<p>Update(2010/7/27): Bundle 1.0.0 之後不需要 bundle lock 了，只要 bundle install 就會自動 lock。</p>
<p><a href="http://gembundler.com/ "><img src="http://gembundler.com/images/bundler-small.png"></a></p>
<p><a href="http://gembundler.com/ ">Bundler</a> 是一套為了 Rails3 所打造的全新 Gem dependencies 管理工具：一套基於 Rubygems 的更高階套件管理工具，適合讓 Application 管理多套 Gems 依存關係的複雜情境。而你在 Rails3 中 (Bundler 不只用在 Rails3，其他例如 Sinatra 或是 Rails2 也都可以使用) 要使用的 Gems，也都必須宣告在它的 Gemfile 裡，沒寫在裡面的話，就算手動 require 也找不到。這跟已往你可以直接 require 任意  rubygems 不同，在使用 Bundler 的環境中，要 require 什麼 rubygems 必須透過 Gemfile 管理。</p>
<p>Gemfile 的寫法大致如下：</p>
<pre>
<code>
  # 第二個參數可以指定版本
  gem "rails", "3.0.0.beta3" 

  # 如果 require 的檔名不同，可以加上 :require
  gem "sqlite3-ruby", :require => "sqlite3"

  # 可以用 Git 當做來源，甚至可以指定 branch, tag 或 ref。
  gem 'authlogic', :git => 'git://github.com/odorcicd/authlogic.git',
                            :branch => 'rails3'

  # 可以直接用電腦裡的其他目錄
  gem "rails", :path => '/Users/ihower/github/rails'

  # Group 功能可以讓特定環境才會載入
  group :test do
    gem "rspec-rails", ">= 2.0.0.beta.8"
    gem "webrat"
  end

</code>
</pre>
<p>設定好 Gemfile 之後，我們有一些指令可以用：</p>
<ul>
<li>bundle check 可以檢查目前缺少哪些 rubygem，然後你可以手動透過 sudo gem install 安裝到系統裡。</li>
<li>bundle install 安裝所有需要的套件。如果系統已經有裝了，就用系統的，不然會裝到 $BUNDLE_PATH 下，預設是你家目錄 ~/.bundle (因此請不要用 sudo 執行 bundle install)。如果來源是 git (例如上述的 authlogic)，每次執行 bundle install 就會自動 git pull 更新，十分方便。</li>
<li>bundle lock 和 bundle unlock 會做 snapshotting 記錄下目前所有套件的版本在 Gemfile.lock，建議這個檔案也一起 commit 出去。適合要佈署或多人開發時，可以確保大家的版本都一致。</li>
<li>bundle package 如果你的 Server 沒聯外網路，或是怕 rubygems.org 連不上，可以用這個指令把所有套件都打包到 vendor/cache 下。基本上，跟以往 Rails 1.X 2.X 時代佈署時會建議你盡量打包依存套件並 commit 出去，在使用 Bundler 後已經大大地不需要了，因為透過 bundle lock 我們就可以確保每台機器上執行的套件版本一致。</li>
<li>bundle exec 因為 Bundle 可以說是獨立出一個套件環境，所以如果有非 Rails 的指令需要執行，而且你的系統 Gems 又沒有安裝，那就會需要透過 bundle exec XXX 來執行。例如 bundle exec cucumber。</li>
<li>bundle show gem_name 可以查看這個 gem 的目錄位置</li>
<li>bundle open gem_name 可以用編輯器打開這個 gem 的目錄</li>
</ul>
<p>開發 Rails3 實際用一陣子之後，發現很偏好將套件裝成 Gem 了(如果有提供 Gem 版的話)，之前 Rails 1.X 2.X 時代會比較喜歡裝成 Plugin，因為想說別人要裝 Gem 可能會有問題，以及佈署也怕出包。但是有了 Bundler 之後，只要 Bundle install 就可以裝好並確保大家的版本一致會動。不像已往的 rake gems:install 超不可靠。可以透過 Bundle 裝這些依存套件也減少了需要 commit 出去的 vendor/plugin 檔案，讓你的專案 repository 變乾淨了。另外，我也超喜歡的 Bundler 可以支援 Git 來源，只要 bundle install 就會更新，不需要額外的管理工具去煩惱更新 plugins。</p>
<p>其他推薦閱讀:</p>
<ul>
<li><a href="http://www.railsdispatch.com/posts/bundler">Library Management Gets an Update in Rails 3</a>: 一般性介紹</li>
<li><a href="http://asciicasts.com/episodes/201-bundler">ASCIIcasts 201: Bundler </a>: 一般性介紹</li>
<li><a href="http://yehudakatz.com/2009/11/03/using-the-new-gem-bundler-today/"> Using the New Gem Bundler Today</a>: 有 Bundler 的設計目標，推薦看第一段即可。</li>
<li><a href="http://yehudakatz.com/2010/02/09/using-bundler-in-real-life/">Using Bundler in Real Life</a>:  Bundle 的使用情境介紹，非常推薦一看</li>
<li><a href="http://yehudakatz.com/2010/04/12/some-of-the-problems-bundler-solves/">Some of the Problems Bundler Solves</a>: 深入舉例 Bundler 要解決的問題，為什麼單靠 Rubygems 和之前的 config.gem 做不到。有時間的話，也推薦一看。
<p>   例如，其中最主要解決的問題是，目前的 Rubygems 同一時間只能 require 一個版本，所以如果你有兩個套件有不同版本的需求，例如一個套件指定需要 rspec 1.1.12，另一個指定需要 1.2.0。那就爆炸了，會出現 can&#8217;t activate rspec(= 1.1.12 runtime), already activated rspec-1.2.0 的錯誤。</li>
<li><a href="http://yehudakatz.com/2010/04/21/named-gem-environments-and-bundler">Named Gem Environments and Bundler</a>: 深入解釋了 Bundler 如何處理 dependency 問題</li>
<li><a href="http://yehudakatz.com/2010/05/09/the-how-and-why-of-bundler-groups/">The How and Why of Bundler Groups</a>: 深入解釋 Group 功能</li>
<li>Yuhada 在 RubyConf 2009 的演講： <a href="http://rubyconf2009.confreaks.com/20-nov-2009-10-25-polishing-rubygems-yehuda-katz.html">Polishing Rubygems</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/4464/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>我的 QA 時間：Ruby Wednesday 定期聚會</title>
		<link>http://ihower.tw/blog/archives/4454</link>
		<comments>http://ihower.tw/blog/archives/4454#comments</comments>
		<pubDate>Wed, 12 May 2010 13:31:51 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=4454</guid>
		<description><![CDATA[最近其實收到不少人來信問 Rails 問題，但是有些問題(特別是入門問題)用 E-mail 往返實在太沒效率了(一來我看不到你的程式碼，二來我也不了解你的程度)，如果當面溝通跟示範，想必能夠更快更全面地解決你的問題。對我來說，當面聊也比較有趣，能有更多的交流學習。
完整的公告詳見 Ruby Wednesday 定期聚會，我每週三晚上會出現在生態綠，如果有意外的話(例如：那天我沒空)，請注意我的 Twitter。
]]></description>
			<content:encoded><![CDATA[<p>最近其實收到不少人來信問 Rails 問題，但是有些問題(特別是入門問題)用 E-mail 往返實在太沒效率了(一來我看不到你的程式碼，二來我也不了解你的程度)，如果當面溝通跟示範，想必能夠更快更全面地解決你的問題。對我來說，當面聊也比較有趣，能有更多的交流學習。</p>
<p>完整的公告詳見 <a href="http://ruby.tw/post/592398890/ruby-wednesday">Ruby Wednesday 定期聚會</a>，我每週三晚上會出現在生態綠，如果有意外的話(例如：那天我沒空)，請注意我的 <a href="http://twitter.com/ihower">Twitter</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/4454/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>校園自由軟體工作坊 &#8211; Meet Ruby on Rails</title>
		<link>http://ihower.tw/blog/archives/4320</link>
		<comments>http://ihower.tw/blog/archives/4320#comments</comments>
		<pubDate>Mon, 03 May 2010 14:20:12 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=4320</guid>
		<description><![CDATA[Update: 投影片下載：遇見 Ruby on Rails。
遇見 Ruby on Rails
View more presentations from Wen-Tien Chang.

這週三 (2010/5/5) 晚上我在台大有一場 &#8220;Meet Ruby on Rails&#8221; 的演講，是由 OSSF 和台大資工系學會所合辦的工作坊。
不同於上次在清大的校園課程，這次只有安排 talk，沒有安排電腦教室給學員實作。給大學生講這個題目，我目前想要多準備一點軟性題目，少談一點程式碼。像是介紹 Web 軟體開發產業、為什麼採用 Web framework、為什麼用 Rails? 為什麼用 scripting 動態語言? 為什麼用 Ruby? 以及除了學校課程以外，我認為作為一個 Web-based 軟體設計師，可以學習的方向。當然，還有 Rails 的 live demo。
某方面來說，雖然題目是遇見 Ruby on Rails，但是我希望也可以讓聽眾遇見 Web application 軟體開發的樂趣。台灣的資工系學生畢業之後，大部分都投入硬體相關產業吧 (不同於美國的軟體業產值超過硬體，台灣的軟體業產值只有硬體的九分之一，真是九牛一毛啊 :~ )。如果這場演講可以讓他們多了解 Web 軟體產業，無論是不是喜歡 Ruby 或 Rails (就算是喜歡上 [...]]]></description>
			<content:encoded><![CDATA[<p>Update: 投影片下載：<a href="http://www.slideshare.net/ihower/meet-ruby-on-rails">遇見 Ruby on Rails</a>。</p>
<div style="width:425px" id="__ss_3973821"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ihower/meet-ruby-on-rails" title="遇見 Ruby on Rails">遇見 Ruby on Rails</a></strong><object id="__sse3973821" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=meet-rails-100505034826-phpapp01&#038;stripped_title=meet-ruby-on-rails" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse3973821" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=meet-rails-100505034826-phpapp01&#038;stripped_title=meet-ruby-on-rails" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ihower">Wen-Tien Chang</a>.</div>
</div>
<p>這週三 (2010/5/5) 晚上我在台大有一場 &#8220;<a href="http://whoswho.openfoundry.org/workshop/details/86--meet-ruby-on-rails.html">Meet Ruby on Rails</a>&#8221; 的演講，是由 <a href="http://www.openfoundry.org">OSSF</a> 和台大資工系學會所合辦的工作坊。</p>
<p>不同於上次在清大的校園課程，這次只有安排 talk，沒有安排電腦教室給學員實作。給大學生講這個題目，我目前想要多準備一點軟性題目，少談一點程式碼。像是介紹 Web 軟體開發產業、為什麼採用 Web framework、為什麼用 Rails? 為什麼用 scripting 動態語言? 為什麼用 Ruby? 以及除了學校課程以外，我認為作為一個 Web-based 軟體設計師，可以學習的方向。當然，還有 Rails 的 live demo。</p>
<p>某方面來說，雖然題目是遇見 Ruby on Rails，但是我希望也可以讓聽眾遇見 Web application 軟體開發的樂趣。台灣的資工系學生畢業之後，大部分都投入硬體相關產業吧 (不同於美國的軟體業產值超過硬體，台灣的軟體業產值只有硬體的九分之一，真是九牛一毛啊 :~ )。如果這場演講可以讓他們多了解 Web 軟體產業，無論是不是喜歡 Ruby 或 Rails (就算是喜歡上 Python, Perl 也不錯)，那就達到我演講的目的了。</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/4320/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Rails3 如何寫 Helper 可以傳 Block 參數</title>
		<link>http://ihower.tw/blog/archives/4225</link>
		<comments>http://ihower.tw/blog/archives/4225#comments</comments>
		<pubDate>Mon, 05 Apr 2010 19:07:08 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=4225</guid>
		<description><![CDATA[ Rails3 beta2 開始確定新的 &#60;%= %> 的用法了，像是 form_for, div_for 等要改成  &#60;%= %> 而不是我們習慣已久的  &#60;% %>，主要是因為這樣統一了 &#60;%= %> 就表示內容會輸出的慣例。目前是兩種寫法都可以，只是本來的寫法會有警告訊息 DEPRECATION WARNING: &#60;% %> style block helpers are deprecated. Please use &#60;%= %>，應該到 Rails 3.1 就會正式移除。用法可以參考 ERB Blocks in Rails 3 一文。
而我這篇接下來要示範的是，如果我們想要自己寫一個 helper，可以接受 block 參數要怎麼寫? 例如在 ERB 中，我們希望這樣的程式可以輸出 header blah footer 字串：


# Rails2
&#60;% my_helper do [...]]]></description>
			<content:encoded><![CDATA[<p> Rails3 <a href="http://weblog.rubyonrails.org/2010/4/1/rails-3-0-second-beta-release">beta2</a> 開始確定新的 &lt;%= %> 的用法了，像是 form_for, div_for 等要改成  &lt;%= %> 而不是我們習慣已久的  &lt;% %>，主要是因為這樣統一了 &lt;%= %> 就表示內容會輸出的慣例。目前是兩種寫法都可以，只是本來的寫法會有警告訊息 DEPRECATION WARNING: &lt;% %> style block helpers are deprecated. Please use &lt;%= %>，應該到 Rails 3.1 就會正式移除。用法可以參考 <a href="http://asciicasts.com/episodes/208-erb-blocks-in-rails-3">ERB Blocks in Rails 3</a> 一文。</p>
<p>而我這篇接下來要示範的是，如果我們想要自己寫一個 helper，可以接受 block 參數要怎麼寫? 例如在 ERB 中，我們希望這樣的程式可以輸出 header blah footer 字串：</p>
<pre>
<code>
# Rails2
&lt;% my_helper do %>
    blah
&lt;% end %>
</code>
</pre>
<p>在 Rails2 的話，如果有包 Block 無論如何都必須用 &lt;% 而不能用 &lt;%=，不然一定會有錯誤訊息。而這個 helper 最常寫成這樣:</p>
<pre>
<code>
# Rails2
def my_helper
  concat("header")
  yield
  concat("footer")
end
</code>
</pre>
<p>或是:</p>
<pre>
<code>
# Rails2
def my_helper(&#038;block)
   tmp = with_output_buffer(&#038;block)
   concat("header #{tmp} footer")
end
</code>
</pre>
<p>在 Rails2 中，我們得用 concat 表示輸出到 ERB (這算是一個密招，沒人教還真的不會)。但是在 Rails3，則被改成比較直覺的:</p>
<pre>
<code>
# Rails3
&lt;%= my_helper do %>
  blah
&lt;% end %>
</pre>
<p></code></p>
<p> 以及</p>
<pre>
<code>
# Rails3
def my_helper(&#038;block)
  tmp = with_output_buffer(&#038;block)
  "header #{tmp} footer"
end
</code>
</pre>
<p>在 Rails3 就不需要用 concat 了，helper 的回傳值透過 &lt;%= 就會輸出在 ERB 上。</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/4225/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby Tuesday #11 開放報名中</title>
		<link>http://ihower.tw/blog/archives/4157</link>
		<comments>http://ihower.tw/blog/archives/4157#comments</comments>
		<pubDate>Mon, 29 Mar 2010 22:00:42 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=4157</guid>
		<description><![CDATA[一場接一場的 Ruby Tuesday 聚會的第十一場由 tka 和 godfat 帶來 Rails integration testing using cucumber+webrat+selenium 和 EventMachine 兩場演講。
時間: 2010/4/13（週二）晚上七點到九點。
地點: 台北市 果子咖啡
報名網頁: http://registrano.com/events/ruby-tuesday-11
]]></description>
			<content:encoded><![CDATA[<p>一場接一場的 Ruby Tuesday 聚會的第十一場由 <a href="http://www.tkalu.com/blog/">tka</a> 和 <a href="http://blogger.godfat.org/">godfat</a> 帶來 Rails integration testing using cucumber+webrat+selenium 和 EventMachine 兩場演講。</p>
<p>時間: 2010/4/13（週二）晚上七點到九點。</p>
<p>地點: 台北市 果子咖啡</p>
<p>報名網頁: <a href="http://registrano.com/events/ruby-tuesday-11">http://registrano.com/events/ruby-tuesday-11</a></p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/4157/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby on Rails Performance 最佳實務</title>
		<link>http://ihower.tw/blog/archives/4098</link>
		<comments>http://ihower.tw/blog/archives/4098#comments</comments>
		<pubDate>Tue, 23 Mar 2010 07:00:05 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=4098</guid>
		<description><![CDATA[這是我 2/26 在中研院 OSSF 工作坊和 3/23 在 Ruby Tuesday 所演講的題目之二。
Rails Performance
View more presentations from Wen-Tien Chang.

關於 Performance，有四個最好不要做的事情: 

過早最佳化
亂猜哪裡慢
到處做快取
與 Framework 過不去，硬要 Hack 它

然後有五條關於 Performance 的須知: 

演算法的改良永遠勝過硬擠程式碼
一般來說，程式碼維護性的重要性勝過效能
只最佳化最需要的部份 (80/20法則)
測量再測量，最佳化前、最佳化後都要測量
必須與程式碼彈性做平衡。有時候做了最佳化之後(例如快取)，會犧牲掉一些彈性。

其他就看投影片吧。這份投影片主要還是關注在 Web application layer，也就是 Ruby 程式語言和 Ruby on Rails 上。有點小可惜的是篇幅和準備時間所限，關於 Front-end performance、NoSQL: Key-value stores 和 HTTP Caching 這三個主題是我覺得可以多講一點的東西。
有了效能，也許你會想進一步知道如何做 Scaling? 不同於 Performance 探討單一台 application server 可以服務多少 requests，Scaling 要探討的問題是如何擴展架構到多台伺服器上來服務更多流量。當然 Performance 會是做 Scaling [...]]]></description>
			<content:encoded><![CDATA[<p>這是我 2/26 在中研院 OSSF 工作坊和 3/23 在 Ruby Tuesday 所演講的題目之二。</p>
<div style="width:425px" id="__ss_3299364"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ihower/rails-performance" title="Rails Performance">Rails Performance</a></strong><object width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rails-performance-2010226-100228083842-phpapp01&#038;stripped_title=rails-performance" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rails-performance-2010226-100228083842-phpapp01&#038;stripped_title=rails-performance" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ihower">Wen-Tien Chang</a>.</div>
</div>
<p>關於 Performance，有四個最好不要做的事情: </p>
<ul>
<li>過早最佳化</li>
<li>亂猜哪裡慢</li>
<li>到處做快取</li>
<li>與 Framework 過不去，硬要 Hack 它</li>
</ul>
<p>然後有五條關於 Performance 的須知: </p>
<ul>
<li>演算法的改良永遠勝過硬擠程式碼</li>
<li>一般來說，程式碼維護性的重要性勝過效能</li>
<li>只最佳化最需要的部份 (80/20法則)</li>
<li>測量再測量，最佳化前、最佳化後都要測量</li>
<li>必須與程式碼彈性做平衡。有時候做了最佳化之後(例如快取)，會犧牲掉一些彈性。</li>
</ul>
<p>其他就看投影片吧。這份投影片主要還是關注在 Web application layer，也就是 Ruby 程式語言和 Ruby on Rails 上。有點小可惜的是篇幅和準備時間所限，關於 Front-end performance、NoSQL: Key-value stores 和 HTTP Caching 這三個主題是我覺得可以多講一點的東西。</p>
<p>有了效能，也許你會想進一步知道如何做 Scaling? 不同於 Performance 探討單一台 application server 可以服務多少 requests，Scaling 要探討的問題是如何擴展架構到多台伺服器上來服務更多流量。當然 Performance 會是做 Scaling 的一個重要的因素，不過 Scaling 需要考量的地方又更多了，包括:</p>
<ul>
<li>Asynchrony Processing (Message queue)</li>
<li>Partition Component using SOA</li>
<li>HTTP Reverse Proxy Caching</li>
<li>Distributed Filesystem/Database</li>
</ul>
<p>其中 Asynchrony Processing 和 SOA 的部份，我在 <a href="http://ihower.tw/blog/archives/3589">Distributes Ruby and Rails</a> 的演講有分享過。</p>
<p>xdite 也有針對 Scaling Rails Site 這個主題寫了一系列的 Scaling Rails Site: Reading Material 來介紹: <a href="http://blog.xdite.net/?p=1597">#1</a>, <a href="http://blog.xdite.net/?p=1617">#2</a>, <a href="http://blog.xdite.net/?p=1664">#3</a>, <a href="http://blog.xdite.net/?p=1682">#4</a>, <a href="http://blog.xdite.net/?p=1704">#5</a></p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/4098/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Ruby on Rails Security 最佳實務</title>
		<link>http://ihower.tw/blog/archives/4096</link>
		<comments>http://ihower.tw/blog/archives/4096#comments</comments>
		<pubDate>Mon, 22 Mar 2010 16:36:39 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=4096</guid>
		<description><![CDATA[這是我 2/26 在中研院 OSSF 工作坊和 3/23  在 Ruby Tuesday 所演講的題目之一。
Ruby on Rails 要談的 Security 網站安全，主要在 Web application layer 的範圍(這也是最容易被攻擊的部分)，像是 XSS、CSRF、Session Hijacking 跟 Fixation、SQL Injection 等等都是所有 Web 應用程式必須處理的問題。也有一些是 Rails 為了程式方便性而製造出來的問題，像是 Mass assignment、Unscoped finds、Controller Exposing methods 等等。
Rails Security
View more presentations from Wen-Tien Chang.

會講的內容看投影片就可以了，這裡我想特別提一下我的開場跟一個觀念:
我的開場引用了 PHP Security Guide: Overview 介紹什麼是 Security，我很喜歡：
1. 安全性是相對的，不是一個功能。碰過太多客戶要求 &#8220;網站要絕對安全，不能被 HACK&#8221;，這實在太強人所難了。安全性就跟溫度一樣，相對熱、相對冷。安全性也是相對安全、相對不安全的，而不是像功能說有或沒有。
2. 承上，要越安全，就給花越多成本去做。不過呢，不需要多花什麼錢，就可以很簡單做到足夠地安全。如果要非常非常安全，就會非常非常貴了。所以請考量你的預算。
3. 必須要與使用性(usability)做平衡。很多時候，安全性跟使用性會是衝突的，想要越多安全性，就給犧牲掉一些使用上的方便性。
4. 安全性必須是網站程式設計過程中的一部分，而不是最後才加上去。
而想提的寫程式觀念是我看 Security [...]]]></description>
			<content:encoded><![CDATA[<p>這是我 2/26 在中研院 OSSF 工作坊和 3/23  在 Ruby Tuesday 所演講的題目之一。</p>
<p>Ruby on Rails 要談的 Security 網站安全，主要在 Web application layer 的範圍(這也是最容易被攻擊的部分)，像是 XSS、CSRF、Session Hijacking 跟 Fixation、SQL Injection 等等都是所有 Web 應用程式必須處理的問題。也有一些是 Rails 為了程式方便性而製造出來的問題，像是 Mass assignment、Unscoped finds、Controller Exposing methods 等等。</p>
<div style="width:425px" id="__ss_3299368"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ihower/rails-security-3299368" title="Rails Security">Rails Security</a></strong><object width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rails-security-2010226-100228083927-phpapp01&#038;stripped_title=rails-security-3299368" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rails-security-2010226-100228083927-phpapp01&#038;stripped_title=rails-security-3299368" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ihower">Wen-Tien Chang</a>.</div>
</div>
<p>會講的內容看投影片就可以了，這裡我想特別提一下我的開場跟一個觀念:</p>
<p>我的開場引用了 <a href="http://phpsec.org/projects/guide/1.html#1.1">PHP Security Guide: Overview</a> 介紹什麼是 Security，我很喜歡：</p>
<p>1. 安全性是相對的，不是一個功能。碰過太多客戶要求 &#8220;網站要絕對安全，不能被 HACK&#8221;，這實在太強人所難了。安全性就跟溫度一樣，相對熱、相對冷。安全性也是相對安全、相對不安全的，而不是像功能說有或沒有。<br />
2. 承上，要越安全，就給花越多成本去做。不過呢，不需要多花什麼錢，就可以很簡單做到足夠地安全。如果要非常非常安全，就會非常非常貴了。所以請考量你的預算。<br />
3. 必須要與使用性(usability)做平衡。很多時候，安全性跟使用性會是衝突的，想要越多安全性，就給犧牲掉一些使用上的方便性。<br />
4. 安全性必須是網站程式設計過程中的一部分，而不是最後才加上去。</p>
<p>而想提的寫程式觀念是我看 <a href="http://www.pragprog.com/titles/fr_secure/security-on-rails">Security on Rails</a> 一書裡面介紹的 Fail Close，底下第一段是用 Fail open 觀念寫的程式，第二段是用 Fail close。</p>
<pre>
<code>
# fail open way, it’s bad
def show
  @invoice = Invoice.find(params[:id])
  unless @user.validate_code( @invoice.code )
    redirect_to :action => 'not_authorized'
  end
end
</code>
</pre>
<pre>
<code>
# fail close way
def show
  @invoice = Invoice.find(params[:id])
  if @user.validate_code( @invoice.code )
    redirect_to :action => 'authorized
  else
    redirect_to :action => 'not_authorized'
   end
end
</code>
</pre>
<p>其中的端倪就是，在撰寫驗證安全性程式碼的時候，請用 Fail close 的觀念：&#8221;如果條件成功，才允許進行，不然就不允許&#8221;。而不是 Fail open：&#8221;如果條件不成功，才不允許，不然就允許。&#8221;。這個簡單的撰碼觀念，可以減少我們寫出漏洞程式碼的機會。</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/4096/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>使用 A/B Testing 工具引導你做網站設計</title>
		<link>http://ihower.tw/blog/archives/3974</link>
		<comments>http://ihower.tw/blog/archives/3974#comments</comments>
		<pubDate>Sat, 13 Mar 2010 21:34:25 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=3974</guid>
		<description><![CDATA[當你有多個設計選擇，不知道哪一種比較好的時候，A/B testing 可以幫助你測試哪一種比較有效果。例如: 你的網站註冊有兩種設計方式，哪一種讓比較多人註冊呢? 你的購物車按鈕有兩種設計，哪一種比較讓人順利結帳呢? 你的廣告版本有三種，哪一種比較吸引人呢?
別猜了!! 公說公有理，婆說婆有理。讓使用者的實際體驗跟統計結果來告訴你吧。a/b testing 的作法是: 1.輪撥這些選項 2. 設定追蹤點(goal) 3. 一段時間後，觀察哪個選項達成的 goal 比較多。
而 A/B testing 工具可以幫助你很容易做好這些事情: 1. 針對不同人提供不同選項 2. 但讓同一個人看到的都是同一個選項(這是一個重點，不然測試就不準了)，例如透過 cookie 或使用者ID 3. 提供後台報表，並提供分析告訴你這些數據是否有統計學上的顯著差異 4. 方便安裝及使用 5. 夠快，不會對 production site 造成效能負擔
對 Rails 來說，目前有兩套可以考慮使用: A/Bingo 和 Vanity。A/Bingo 很容易安裝使用，功能比較陽春，使用 ActiveRecord 搭配快取(memcached) 來記錄資料。Vanity 功能比較豐富，願景也比較大，提倡了一整套的 Experiment Driven Development 開發方式。它使用了 Redis 來記錄資料。不過他的使用文件似乎沒有跟上程式的更新速度，所以不太好安裝，得去翻 source code。如果你現在就想試試，我會先推薦 A/Bingo 比較容易上手。
如果你不想改 server [...]]]></description>
			<content:encoded><![CDATA[<p>當你有多個設計選擇，不知道哪一種比較好的時候，<a href="http://en.wikipedia.org/wiki/A/B_testing">A/B testing</a> 可以幫助你測試哪一種比較有效果。例如: 你的網站註冊有兩種設計方式，哪一種讓比較多人註冊呢? 你的購物車按鈕有兩種設計，哪一種比較讓人順利結帳呢? 你的廣告版本有三種，哪一種比較吸引人呢?</p>
<p>別猜了!! 公說公有理，婆說婆有理。讓使用者的實際體驗跟統計結果來告訴你吧。a/b testing 的作法是: 1.輪撥這些選項 2. 設定追蹤點(goal) 3. 一段時間後，觀察哪個選項達成的 goal 比較多。</p>
<p>而 A/B testing 工具可以幫助你很容易做好這些事情: 1. 針對不同人提供不同選項 2. 但讓同一個人看到的都是同一個選項(這是一個重點，不然測試就不準了)，例如透過 cookie 或使用者ID 3. 提供後台報表，並提供<a href="http://20bits.com/articles/statistical-analysis-and-ab-testing/">分</a><a href="http://www.cennydd.co.uk/2009/statistical-significance-other-ab-test-pitfalls/">析</a>告訴你這些數據是否有統計學上的顯著差異 4. 方便安裝及使用 5. 夠快，不會對 production site 造成效能負擔</p>
<p>對 Rails 來說，目前有兩套可以考慮使用: <a href="http://www.bingocardcreator.com/abingo">A/Bingo</a> 和 <a href="http://vanity.labnotes.org/">Vanity</a>。A/Bingo 很容易安裝使用，功能比較陽春，使用 ActiveRecord 搭配快取(memcached) 來記錄資料。Vanity 功能比較豐富，願景也比較大，提倡了一整套的 <a href="http://www.infoq.com/news/2010/02/edd-post-agile">Experiment Driven Development</a> 開發方式。它使用了 <a href="http://code.google.com/p/redis/">Redis</a> 來記錄資料。不過他的使用文件似乎沒有跟上程式的更新速度，所以不太好安裝，得去翻 source code。如果你現在就想試試，我會先推薦 A/Bingo 比較容易上手。</p>
<p>如果你不想改 server side 的程式(或是你是不會寫程式的行銷人員)，也可以透過 <a href="https://www.google.com/analytics/siteopt/">Google Website Optimizer</a> 這套工具來做 a/b testing。Google 的方式就單純用 JavaScript 來記錄: 你先告訴 Google 你有哪幾種頁面，例如 Original page、Variation page 1、Variation page 2 三種選項，接著提供 Conversion page 是指達成 goal 的頁面，然後將 Google 會給你 control script 貼到 Original page 去(讓使用者可以輪撥到其他頁面)，以及 tracking script 貼到各個頁面。</p>
<p>最後，A/B Testing 當然也不是萬能的: <a href="http://commetrics.com/articles/supplement-with-qualitative-assessment/">Why A/B testing of web design fails</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/3974/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>深入Rails3: ActiveSupport::Concern</title>
		<link>http://ihower.tw/blog/archives/3949</link>
		<comments>http://ihower.tw/blog/archives/3949#comments</comments>
		<pubDate>Thu, 11 Mar 2010 23:29:45 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=3949</guid>
		<description><![CDATA[(English version)
ActiveSupport::Concern 是 Rails3 做 Modularity 的一個重要的小工具。他的任務是讓管理 modules 之間的 dependencies 變得容易。
假設我們有兩個 Modules 有依存關係，module Bar 依存於 module Foo，然後有一個宿主 Host 類別希望 include Bar 的功能，我們可以這樣寫:


module Foo
   # self.included 這個函式會在 Foo 被 include 時執行
    def self.included(base)
        base.send(:do_host_something) # 對宿主做某些操作，例如增強功能等等
    end
end

module Bar
    [...]]]></description>
			<content:encoded><![CDATA[<p>(<a href="http://en.ihower.tw/post/454873995/rails3-activesupport-concern">English version</a>)</p>
<p>ActiveSupport::Concern 是 Rails3 做 Modularity 的一個重要的小工具。他的任務是讓管理 modules 之間的 dependencies 變得容易。</p>
<p>假設我們有兩個 Modules 有依存關係，module Bar 依存於 module Foo，然後有一個宿主 Host 類別希望 include Bar 的功能，我們可以這樣寫:</p>
<pre>
<code>
module Foo
   # self.included 這個函式會在 Foo 被 include 時執行
    def self.included(base)
        base.send(:do_host_something) # 對宿主做某些操作，例如增強功能等等
    end
end

module Bar
    def self.included(base)
        base.send(:do_host_something)
    end
end

class Host
  include Foo, Bar
end
</code>
</pre>
<p>這有個討厭的缺點就是，我們必須在宿主中同時 include Foo 跟 Bar，也就是要把所有依存的 modules 都 include 進來。這很糟糕啊，為什麼我們需要在 Host 裡面知道這些 modules 的依存關係呢 :/</p>
<p>我們希望能夠將 modules 的依存關係寫在 module 中，而宿主 Host 就只要使用就好了。所以我們試著改寫成:</p>
<pre>
<code>
module Bar
  include Foo # 因為 Bar 依存於 Foo，所以我們在這裡 include 它

  def self.included(base)
    base.send(:do_host_something)
  end

end

class Host
  include Bar # 只要 include Bar 就好，不需要知道 Bar 還依存哪些 modules
end
</code>
</pre>
<p>這樣乍看之下好像沒問題，但是卻有個嚴重的問題導致無法執行，因為 Foo 變成是由 Bar 所 include，所以對 Foo 的 self.included 來說，他的參數 base 變成了 Bar 了，所以他就沒辦法存取到宿主 Host 的任何函式及變數，do_host_something 時就會失敗。</p>
<p>Okay，ActiveSupport::Concern 就是來幫助解決這個難題，我們希望宿主可以不需要知道 modules 之間的 dependencies 關係。dependencies 關係寫在 module 裡面就好了。</p>
<pre>
<code>
require 'active_support/concern'

module Foo
    extend ActiveSupport::Concern
    included do
        self.send(:do_host_something)
    end
end

module Bar
    extend ActiveSupport::Concern
    include Foo # 因為 Bar 依存於 Foo，所以我們在這裡 include 它

    included do
        self.send(:do_host_something)
    end
end

class Host
  include Bar # 只要 include Bar 就好，不需要知道 Bar 還依存哪些 modules
end

</code>
</pre>
<p>如此就搞定了。One more thing，如果你有定義 module ClassMethods 和 module InstanceMethods 在裡面的話，它也會自動幫你載入到宿主裡面去，就不用自己寫 send(:include, InstanceMethods) 跟 send(:extend, ClassMethods) 了。用法舉例：</p>
<pre>
<code>

module Foo
    extend ActiveSupport::Concern
    included do
        self.send(:do_host_something)
    end

   module ClassMethods
      def bite
        # do something
      end
   end

   module InstanceMethods
      def poke
         # do something
      end
   end
end

</code>
</pre>
<p>想知道 ActiveSupport::Concern 到底怎麼實作的話，請看 <a href="http://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb">/activesupport/lib/active_support/concern.rb</a>，只有 29 行，而且 ActiveSupport::Concern 也沒有再依存其他東西了，嘿。</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/3949/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails3 如何換使用 jQuery</title>
		<link>http://ihower.tw/blog/archives/3917</link>
		<comments>http://ihower.tw/blog/archives/3917#comments</comments>
		<pubDate>Fri, 05 Mar 2010 08:56:12 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=3917</guid>
		<description><![CDATA[在 Rails3 中，處理 JavaScript 改採用 UJS 的方式，也就是以往 inline JS 的情況將不復見，link_to_remote 跟 remote_form_for 都沒有了:
例如:

link_to 'Logout', session_path, :method => :delete

產生出來的是:


&#60;a href="/session" data-method="delete" rel="nofollow">Logoout&#60;/a>


例如


link_to 'Ajax delete', person_path(person),
      :remote => true, :confirm => "Are you sure?"


產生出來的是


&#60;a href="/people/1"  data-confirm="Are you sure?" data-method="delete"
             [...]]]></description>
			<content:encoded><![CDATA[<p>在 Rails3 中，處理 JavaScript 改採用 <a href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript">UJS</a> 的方式，也就是以往 inline JS 的情況將不復見，link_to_remote 跟 remote_form_for 都沒有了:</p>
<p>例如:<br />
<code><br />
link_to 'Logout', session_path, :method => :delete<br />
</code><br />
產生出來的是:<br />
<code></p>
<pre>
&lt;a href="/session" data-method="delete" rel="nofollow">Logoout&lt;/a>
</pre>
<p></code><br />
例如<br />
<code></p>
<pre>
link_to 'Ajax delete', person_path(person),
      :remote => true, :confirm => "Are you sure?"
</pre>
<p></code><br />
產生出來的是<br />
<code></p>
<pre>
&lt;a href="/people/1"  data-confirm="Are you sure?" data-method="delete"
              data-remote="true" rel="nofollow">Ajax delete&lt;/a>
# 點下去會向 Server 要求 JavaScript 內容執行
</pre>
<p></code></p>
<p>Rails3 預設還是使用 <a href="http://www.prototypejs.org/">Prototype.js</a>，要換成 <a href="http://jquery.com/">jQuery</a> 非常簡單。首先在產生 rails 專案時，可以輸入 rails your_project -J 就不會產生 Prototype.js 的檔案。</p>
<p>修改 /public/javascripts/rails.js 這個檔案，內容換成 <a href="http://github.com/rails/jquery-ujs/blob/master/src/rails.js">http://github.com/rails/jquery-ujs/blob/master/src/rails.js</a> 這個官方提供的 jQuery js driver。</p>
<p>在 Rails layout 的 HTML head 中加入:<br />
<code></p>
<pre>
&lt;%= csrf_meta_tag %>
&lt;%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js" %>
&lt;%= javascript_include_tag 'rails' %>
</pre>
<p></code></p>
<p>其中 csrf_mate_tag 產生的是做 CSRF 防禦的 authenticity_token，以往這也是 inline 在 HTML 中，現在則是先宣告在 HTML head 中。</p>
<p>另外要提醒你，如果你有使用 RJS 的話，Rails3 的 RJS 還是只會產生 prototype.js 的版本。所以如果非得用 RJS 的話，目前恐怕還是得裝以往 Rails2 用的 <a href="http://github.com/aaronchi/jrails">jRails</a>，這好像有點蠢。也許是時候把 RJS 徹底揚棄，直接寫 jQuery 好了(?)</p>
<p>例如上面的 Ajax delete 例子，它的 controller 跟 js 可以這樣:</p>
<p><code></p>
<pre>
# people_controller.rb
  def destroy
    @person = Person.find(params[:id])
    @person.destroy

    respond_to do |format|
      format.html { redirect_to(people_url) }
      format.js # destroy.js.erb
    end
  end

# destroy.js.erb
jQuery("#&lt;%= dom_id(@person)%>").remove();
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/3917/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
