<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" 
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>syshen&#039;s blog</title>
<link>http://blog.yam.com/syshen</link>
<description>
我不想限定我的 blog 方向，但是在這裡的都是我最認真的紀錄。
  
</description>
<language>zh-tw</language>
<generator>blog.yam.com</generator>
<copyright>All Rights Reserved</copyright>
<item>
  <title>[Rails 筆記] tinyint ?</title>
  <description>
MySQL table 中欄位屬性如果為 tinyint(1) ， Rails 會自動視其為 boolean 值，這個問題害我傷了很久的腦筋，今天找到&lt;a href=&quot;http://railshelp.com/ActiveRecord::ConnectionAdapters::MysqlAdapter&quot; target=_&gt;答案&lt;/a&gt;了：&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;By default, the MysqlAdapter will consider all columns of type tinyint(1) as boolean. If you wish to disable this emulation (which was the default behavior in versions 0.13.1 and earlier) you can add the following line to your environment.rb file:&lt;br /&gt;
&lt;br /&gt;
  ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;

   </description>

<content:encoded><![CDATA[
MySQL table 中欄位屬性如果為 tinyint(1) ， Rails 會自動視其為 boolean 值，這個問題害我傷了很久的腦筋，今天找到<a href="http://railshelp.com/ActiveRecord::ConnectionAdapters::MysqlAdapter" target=_>答案</a>了：<br />
<br />
<blockquote>By default, the MysqlAdapter will consider all columns of type tinyint(1) as boolean. If you wish to disable this emulation (which was the default behavior in versions 0.13.1 and earlier) you can add the following line to your environment.rb file:<br />
<br />
  ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false<br />
</blockquote><br />

]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6735962</link>
  <category>Programming</category>
  <pubDate>Wed, 22 Nov 2006 12:02:28 +0800</pubDate>
</item>
<item>
  <title>ruby plugin for vim</title>
  <description>
一直都是用 vim 寫 Ruby ，一直也都是黑與白，直到今天才熊熊想到，啊，沒有 syntax highlight。雖然 syntax highlight 對我來說沒什麼太大的用途，可是多點色彩，看起來好像會比較專業點，問了一下估狗大神，找到下面這個網址。&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://vim-ruby.rubyforge.org/&quot; target=_&gt;Vim/Ruby Configuration Files&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
抓 gem 檔回來安裝，設定好 vimrc ，人生又回復色彩了。&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://static.flickr.com/114/290573752_efa5fd285d.jpg&quot; /&gt;&lt;br /&gt;

   </description>

<content:encoded><![CDATA[
一直都是用 vim 寫 Ruby ，一直也都是黑與白，直到今天才熊熊想到，啊，沒有 syntax highlight。雖然 syntax highlight 對我來說沒什麼太大的用途，可是多點色彩，看起來好像會比較專業點，問了一下估狗大神，找到下面這個網址。<br />
<br />
<a href="http://vim-ruby.rubyforge.org/" target=_>Vim/Ruby Configuration Files</a><br />
<br />
抓 gem 檔回來安裝，設定好 vimrc ，人生又回復色彩了。<br />
<br />
<img src="http://static.flickr.com/114/290573752_efa5fd285d.jpg" /><br />

]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6671899</link>
  <category>Programming</category>
  <pubDate>Mon, 06 Nov 2006 22:35:06 +0800</pubDate>
</item>
<item>
  <title>網頁自動化測試</title>
  <description>
要作網頁的 Unit test 有幾個工具可以用，例如 Ruby on Rails 本身就有提供 Unit test framework 了，而 PHP 也有幾套可以用，例如 PHPUnit、SimpleTest 以及 Spike PHPCoverage 測 code coverage，除了 RoR 我有用過外，PHP 的那些工具我都沒用過，不過這並不是我這篇想講的重點，我這裡主要是想介紹一個最近在玩的玩具，Web Service 的自動測試工具 - &lt;a href=&quot;http://wtr.rubyforge.org/&quot; target=_&gt;Watir&lt;/a&gt;。&lt;br /&gt;
&lt;br /&gt;
Watir 全名是 Web Application Testing in Ruby ，沒錯！你看到 Ruby 了，他就是用 Ruby 開發的測試架構。Watir 有什麼好處呢？第一，他是用 Ruby 開發，寫 Test Case 也是用 Ruby，感覺就親切許多，第二，他是直接 launch IE，並透過操控 IE 來測試你的 Web Application，所以可以測出一些可能在瀏覽器上才會遇到的問題，第三，寫好 Test Case 後，一切都可以自動化執行，第四，不管你的 Web Application 是用什麼語言寫的，Watir 都可以支援，因為他是啟動 IE 來瀏覽。不過它也有些缺點，第一，目前只支援 Windows 平台，第二，目前只支援 IE 瀏覽器，第三，因為是靠 IE 操作，所以測試時間會較其他測試方法長，不過總是比人工測快許多。&lt;br /&gt;

  &lt;a href=&quot;http://blog.yam.com/syshen/article/6646444&quot;&gt;(觀看全文...)&lt;/a&gt;
   </description>

<content:encoded><![CDATA[
要作網頁的 Unit test 有幾個工具可以用，例如 Ruby on Rails 本身就有提供 Unit test framework 了，而 PHP 也有幾套可以用，例如 PHPUnit、SimpleTest 以及 Spike PHPCoverage 測 code coverage，除了 RoR 我有用過外，PHP 的那些工具我都沒用過，不過這並不是我這篇想講的重點，我這裡主要是想介紹一個最近在玩的玩具，Web Service 的自動測試工具 - <a href="http://wtr.rubyforge.org/" target=_>Watir</a>。<br />
<br />
Watir 全名是 Web Application Testing in Ruby ，沒錯！你看到 Ruby 了，他就是用 Ruby 開發的測試架構。Watir 有什麼好處呢？第一，他是用 Ruby 開發，寫 Test Case 也是用 Ruby，感覺就親切許多，第二，他是直接 launch IE，並透過操控 IE 來測試你的 Web Application，所以可以測出一些可能在瀏覽器上才會遇到的問題，第三，寫好 Test Case 後，一切都可以自動化執行，第四，不管你的 Web Application 是用什麼語言寫的，Watir 都可以支援，因為他是啟動 IE 來瀏覽。不過它也有些缺點，第一，目前只支援 Windows 平台，第二，目前只支援 IE 瀏覽器，第三，因為是靠 IE 操作，所以測試時間會較其他測試方法長，不過總是比人工測快許多。<br />

<a href="http://blog.yam.com/syshen/article/6646444">(觀看全文...)</a>
]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6646444</link>
  <category>Programming</category>
  <pubDate>Wed, 01 Nov 2006 17:48:10 +0800</pubDate>
</item>
<item>
  <title>innerHTML 與 createElement 的差異</title>
  <description>
查了一下網路上有關於 innerHTML 與 createElement() performance 的比較，都是顯示 innerHTML 有較好的 performance ，這跟我以前的印象有蠻大的差距，我一直都以為 innerHTML 會較差，直接 createElement() 以及 appendChild() 會有比較好的 performance，不過既然測試出來的數據都是這樣，看來也應該如此。&lt;br /&gt;
&lt;br /&gt;
innerHTML 的優點是容易實做，程式碼容易維護，再加上 performance 較好，那麼我真的不知道使用 createElement() 跟 appendChild() 的理由為何了。&lt;br /&gt;
&lt;br /&gt;
感謝 midoli 糾正我上一篇文章，我一時不查，以原本的想法觀念，寫了一篇錯誤的文章出來，看來作學問還是要秉持著嚴謹的態度。&lt;br /&gt;

   </description>

<content:encoded><![CDATA[
查了一下網路上有關於 innerHTML 與 createElement() performance 的比較，都是顯示 innerHTML 有較好的 performance ，這跟我以前的印象有蠻大的差距，我一直都以為 innerHTML 會較差，直接 createElement() 以及 appendChild() 會有比較好的 performance，不過既然測試出來的數據都是這樣，看來也應該如此。<br />
<br />
innerHTML 的優點是容易實做，程式碼容易維護，再加上 performance 較好，那麼我真的不知道使用 createElement() 跟 appendChild() 的理由為何了。<br />
<br />
感謝 midoli 糾正我上一篇文章，我一時不查，以原本的想法觀念，寫了一篇錯誤的文章出來，看來作學問還是要秉持著嚴謹的態度。<br />

]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6611365</link>
  <category>Programming</category>
  <pubDate>Tue, 24 Oct 2006 10:24:29 +0800</pubDate>
</item>
<item>
  <title>[AJAX Pattern] Amazon A9 Search</title>
  <description>
&lt;div style=&quot;&quot;&gt; 上次在 Amazon 的 A9 Search 看到一個很有趣的 AJAX 應用，看了就很想自己實作看看，實際上也不困難，如果瞭解 AJAX 的原理，Javascript event 處理等就能寫出來了，所以在這裡介紹給大家看看。&lt;br/&gt; &lt;br/&gt; &lt;font size=&quot;3&quot; style=&quot;FONT-WEIGHT:bold&quot;&gt;[Amazon A9 Search]&lt;/font&gt;&lt;br/&gt; 傳統的搜尋引擎如 Google 或 Yahoo 等，在將搜尋結果丟出來後，會以分頁來顯示這些結果，使用者想要找的結果如果不是在第一頁的話，就會一頁接著一頁向後找尋。這種作法也沒什麼不對，很直覺，但是我看了 A9 的用法後，我反而覺得 A9 的作法更為實際，更加直覺。A9 怎麼操作的？ Scrollbar !&lt;br/&gt; &lt;br/&gt; &lt;a href=&quot;http://www.flickr.com/photos/syshen/271224359/&quot; title=&quot;Photo Sharing&quot;&gt;&lt;img alt=&quot;ss&quot; border=&quot;0&quot; height=&quot;326&quot; src=&quot;http://static.flickr.com/65/271224359_337e698b10.jpg&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;&lt;br/&gt; A9 會先丟出前幾筆的結果於網頁上，例如排名前 20 筆，但是當妳使用 Scrollbar 往下拉動時，更多資料就會源源不絕的顯示出來，同時妳也會發現左邊的 Scrollbar 越來越小，代表資料量越來越多。用寫的來描述這行為實在很難，妳可以上 &lt;a href=&quot;http://www.a9.com&quot; title=&quot;http://www.a9.com&quot;&gt;http://www.a9.com&lt;/a&gt; ，透過實際操作便可瞭解。為什麼說他更直覺呢？因為如果第一次沒看到你想要的資料時，同時妳又看到 scrollbar 在旁邊，直覺上的操作就是會去拉動 scrollbar ，如同妳在 google 的搜尋結果中，也會拉動瀏覽器視窗的 scrollbar 來看底下的資料，如果沒有再點下一頁，所以既然都在拉動 scrollbar 了，何不在同時也去抓新的資料，所以我說他的操作方式更加直覺。&lt;br/&gt; &lt;br/&gt; &lt;font size=&quot;3&quot; style=&quot;FONT-WEIGHT:bold&quot;&gt;[怎麼做？]&lt;/font&gt;&lt;br/&gt; &lt;br/&gt; 假設我們想讓內容顯示在一 DIV 區塊中，藉由使用者拖拉 scrollbar 來動態增加顯示內容的話：&lt;br/&gt; &lt;br/&gt; &lt;span style=&quot;FONT-WEIGHT:bold&quot;&gt;第一步、&lt;/span&gt;於 DIV 區塊上顯示 scrollbar&lt;br/&gt; 這很簡單，只需要透過簡單的 style 屬性設定即可，前提就是妳必須先設定 DIV 區塊高度，並設定屬性 overflow:auto ，例如：&lt;br/&gt; &lt;blockquote&gt;&amp;lt;div id=&quot;content&quot; style=&quot;width:490px;height:490px; overflow: auto&quot;&amp;gt;&lt;br/&gt; ....&amp;nbsp; 妳想要顯示的內容。&lt;br/&gt; &amp;lt;/div&amp;gt;&lt;br/&gt; &lt;/blockquote&gt;當妳於 DIV 區塊中的內容超過 DIV 高度時，瀏覽器便會於右邊出現 scrollbar。&lt;br/&gt; &lt;br/&gt; &lt;span style=&quot;FONT-WEIGHT:bold&quot;&gt;第二步、&lt;/span&gt;攔截使用者 scrolling 動作&lt;br/&gt; 檢而言之，攔截該 DIV 區塊的 onscroll 事件，例如：&lt;br/&gt; &lt;blockquote&gt;// 注意：以下程式碼使用 prototype.js 語法&lt;br/&gt; $(&#039;content&#039;).onscroll = checkScroll;&lt;br/&gt; &lt;/blockquote&gt;checkScoll 函式便是我們想要處理 scrolling event 的函式。&lt;br/&gt; &lt;br/&gt; &lt;span style=&quot;FONT-WEIGHT:bold&quot;&gt;第三步、&lt;/span&gt;呼叫 AJAX，向伺服器要新資料，例如：&lt;br/&gt; &lt;blockquote&gt;// 注意：以下程式碼使用 prototype.js 物件&lt;br/&gt; var opts = new Object;&lt;br/&gt; opts.parameters = &#039;page=&#039; + page_num;&lt;br/&gt; opts.onComplete = showResponse;&lt;br/&gt; var ajax = new Ajax.Request (url, opts);&lt;br/&gt; page_num ++;&lt;br/&gt; &lt;/blockquote&gt;&lt;br/&gt; &lt;span style=&quot;FONT-WEIGHT:bold&quot;&gt;第四步、&lt;/span&gt;取得 AJAX 回傳結果，也就是上述程式碼中的 showResponse 函式：&lt;br/&gt; &lt;blockquote&gt;function showResponse(origReq) {&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; $(&#039;content&#039;).innerHTML += origReq.responseText;&lt;br/&gt; }&lt;br/&gt; &lt;/blockquote&gt;看，這樣就完成了！超簡單！所以來 re-factoring 一下。&lt;br/&gt; &lt;br/&gt; &lt;font size=&quot;3&quot; style=&quot;FONT-WEIGHT:bold&quot;&gt;[Refactoring]&lt;/font&gt;&lt;br/&gt; 我們將這樣的概念稍微把他物件化，讓它可以重複被使用，而且增加一些保護措施。&lt;br/&gt; &lt;blockquote&gt;function showResponse(origReq) {&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var nav = $(this.nav.contentID);&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var last = nav.lastChild;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; while (last.nodeName != &#039;DIV&#039;) {&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; last = last.previousSibling;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nav.removeChild (last);&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nav.innerHTML += origReq.responseText;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nav.innerHTML += &#039;&amp;lt;div style=&quot;background: #AAAAAA;&quot;&amp;gt;Fetching ... &amp;lt;/div&amp;gt;&#039;;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.fetching = false;&lt;br/&gt; }&lt;br/&gt; &lt;br/&gt; function ScrollNav(contentID, url) {&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.contentID = contentID;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.contentObj = $(contentID);&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.contentObj.nav = this;&amp;nbsp; // 記錄目前物件，給 checkScroll 函式使用&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.fetching = false;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.scrollTop = this.contentObj.scrollTop; // 記錄一開始 scrollTop&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.scrollHeight = this.contentObj.scrollHeight; // 記錄一開始 scrollHeight&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.url = url;&lt;br/&gt; &lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.idx = 0; // page number&lt;br/&gt; &lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.checkScroll = function() {&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(this.nav.scrollTop == this.scrollTop)&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (this.fetching)&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;br/&gt; &lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.nav.scrollTop = this.scrollTop;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (this.scrollHeight == parseInt(this.style.height) + this.scrollTop) {&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var opts = new Object;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; opts.parameters = &#039;page=&#039; + this.nav.idx;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; opts.onComplete = showResponse.bind(this);&lt;br/&gt; &lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var ajax = new Ajax.Request(this.nav.url, opts);&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.fetching = true;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.nav.idx ++;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br/&gt; &lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; // 攔截 onscroll event&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.contentObj.onscroll = this.checkScroll;&lt;br/&gt; }&lt;br/&gt; &lt;br/&gt; function init() {&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var nav = new ScrollNav(&#039;content&#039;, &#039;scroll_test.php&#039;);&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var nav = new ScrollNav(&#039;content2&#039;, &#039;scroll_test2.php&#039;);&lt;br/&gt; }&lt;br/&gt; &lt;/blockquote&gt;&lt;br/&gt; 這裡頭有個 ScrollNav 物件，就是將這些東西都包進去了，此外，於 checkScroll 函式中會檢查 event 是否被重複攔截，以及檢查目前 scrollbar 是否被拉動至最下方，唯有 scrollbar 被拉到最下面時，我們才向伺服器要求更多的資料，避免頻寬資源的浪費。scrollTop 跟 scrollHeight 都是內建的屬性，scrollTop 代表目前顯示的 view 距離最上方多少有 pixel，而 scrollHeight 則代表內容 view 的總長，同樣是 pixel，當妳資料越塞越多時，scrollTop 跟 scrollHeight 都會跟著增加，如果要判斷 scrollbar 是否為拉到最下方，最簡單的方法便是計算 scrollTop 和 DIV 區塊的高度總長是否等於 scrollHeight 即可。&lt;br/&gt; &lt;br/&gt; 至於在 showResponse() 函式中，我們會在每次抓到的新資料中都塞進個「Fetching ...」的字眼，代表目前正在抓取更多資料，這是一種小技巧，就像在大部分的 AJAX Pattern 中都可以看到的 Loading 字眼，妳也可以用個 gif 動畫來取代，只不過每次取得新資料時，必須將上一個「Fetching ...」移除。&lt;br/&gt; &lt;br/&gt; 想看結果嗎？請看 &lt;a href=&quot;http://gais4.cs.ccu.edu.tw/%7Esys89/scroll.html&quot; title=&quot;Demo&quot;&gt;Demo&lt;/a&gt; 。裡頭有兩個 DIV 區塊，左邊的 DIV 區塊所 request 的 PHP 檔執行較快，而右邊的每次都會 sleep 5 秒鐘，所以感覺起來比較慢，拉動兩個 scrollbar 妳便可以發覺兩者間的不同。&lt;br/&gt; &lt;br/&gt; &lt;font size=&quot;3&quot;&gt;&lt;span style=&quot;FONT-WEIGHT:bold&quot;&gt;[其他問題？]&lt;/span&gt;&lt;/font&gt;&lt;br/&gt; 目前這個範例還有些存在性的問題：&lt;br/&gt; &lt;ol&gt; &lt;li&gt; 別吃光 browser 的記憶體了。塞資料時要設立停止點，別一直狂塞，吃光妳瀏覽器的記憶體了。&lt;/li&gt; &lt;li&gt; 不一定要拉動到最下方才開始抓取資料，可以在使用者的 scrollbar 接近最下方時，便向伺服器要求新資料，可以達到更順暢的操作。&lt;br/&gt;&lt;/li&gt; &lt;/ol&gt; &lt;br/&gt; &lt;br/&gt; &lt;font size=&quot;3&quot;&gt;&lt;span style=&quot;FONT-WEIGHT:bold&quot;&gt;[這可以應用在哪？]&lt;/span&gt;&lt;/font&gt;&lt; br/&gt; 我想這些概念，實作都是很簡單，重要的是妳有沒有創意，有沒有想到這些 idea，以及怎麼應用在妳的網頁中，這我想應該讓妳自己去想想看，不過我覺得可以應用在某些功能上，例如 blog 留言版，留言版並不是每個人都想看，如果留言眾多時，每次都將留言塞到使用者的瀏覽器上也不甚合理，如果透過類似的方法，先讓使用者看到最新的留言，如果想繼續看下去，只需要拉動 scrollbar 即可。應該還可以想出更多有趣的應用，不過還是大家自己想想看吧。&lt;br/&gt;  &lt;br/&gt;  &lt;br/&gt;  &lt;br/&gt;  &lt;br/&gt; &lt;/div&gt;

   </description>

<content:encoded><![CDATA[
<div style=""> 上次在 Amazon 的 A9 Search 看到一個很有趣的 AJAX 應用，看了就很想自己實作看看，實際上也不困難，如果瞭解 AJAX 的原理，Javascript event 處理等就能寫出來了，所以在這裡介紹給大家看看。<br/> <br/> <font size="3" style="FONT-WEIGHT:bold">[Amazon A9 Search]</font><br/> 傳統的搜尋引擎如 Google 或 Yahoo 等，在將搜尋結果丟出來後，會以分頁來顯示這些結果，使用者想要找的結果如果不是在第一頁的話，就會一頁接著一頁向後找尋。這種作法也沒什麼不對，很直覺，但是我看了 A9 的用法後，我反而覺得 A9 的作法更為實際，更加直覺。A9 怎麼操作的？ Scrollbar !<br/> <br/> <a href="http://www.flickr.com/photos/syshen/271224359/" title="Photo Sharing"><img alt="ss" border="0" height="326" src="http://static.flickr.com/65/271224359_337e698b10.jpg" width="500" /></a><br/> A9 會先丟出前幾筆的結果於網頁上，例如排名前 20 筆，但是當妳使用 Scrollbar 往下拉動時，更多資料就會源源不絕的顯示出來，同時妳也會發現左邊的 Scrollbar 越來越小，代表資料量越來越多。用寫的來描述這行為實在很難，妳可以上 <a href="http://www.a9.com" title="http://www.a9.com">http://www.a9.com</a> ，透過實際操作便可瞭解。為什麼說他更直覺呢？因為如果第一次沒看到你想要的資料時，同時妳又看到 scrollbar 在旁邊，直覺上的操作就是會去拉動 scrollbar ，如同妳在 google 的搜尋結果中，也會拉動瀏覽器視窗的 scrollbar 來看底下的資料，如果沒有再點下一頁，所以既然都在拉動 scrollbar 了，何不在同時也去抓新的資料，所以我說他的操作方式更加直覺。<br/> <br/> <font size="3" style="FONT-WEIGHT:bold">[怎麼做？]</font><br/> <br/> 假設我們想讓內容顯示在一 DIV 區塊中，藉由使用者拖拉 scrollbar 來動態增加顯示內容的話：<br/> <br/> <span style="FONT-WEIGHT:bold">第一步、</span>於 DIV 區塊上顯示 scrollbar<br/> 這很簡單，只需要透過簡單的 style 屬性設定即可，前提就是妳必須先設定 DIV 區塊高度，並設定屬性 overflow:auto ，例如：<br/> <blockquote>&lt;div id="content" style="width:490px;height:490px; overflow: auto"&gt;<br/> ....&nbsp; 妳想要顯示的內容。<br/> &lt;/div&gt;<br/> </blockquote>當妳於 DIV 區塊中的內容超過 DIV 高度時，瀏覽器便會於右邊出現 scrollbar。<br/> <br/> <span style="FONT-WEIGHT:bold">第二步、</span>攔截使用者 scrolling 動作<br/> 檢而言之，攔截該 DIV 區塊的 onscroll 事件，例如：<br/> <blockquote>// 注意：以下程式碼使用 prototype.js 語法<br/> $('content').onscroll = checkScroll;<br/> </blockquote>checkScoll 函式便是我們想要處理 scrolling event 的函式。<br/> <br/> <span style="FONT-WEIGHT:bold">第三步、</span>呼叫 AJAX，向伺服器要新資料，例如：<br/> <blockquote>// 注意：以下程式碼使用 prototype.js 物件<br/> var opts = new Object;<br/> opts.parameters = 'page=' + page_num;<br/> opts.onComplete = showResponse;<br/> var ajax = new Ajax.Request (url, opts);<br/> page_num ++;<br/> </blockquote><br/> <span style="FONT-WEIGHT:bold">第四步、</span>取得 AJAX 回傳結果，也就是上述程式碼中的 showResponse 函式：<br/> <blockquote>function showResponse(origReq) {<br/> &nbsp;&nbsp;&nbsp; $('content').innerHTML += origReq.responseText;<br/> }<br/> </blockquote>看，這樣就完成了！超簡單！所以來 re-factoring 一下。<br/> <br/> <font size="3" style="FONT-WEIGHT:bold">[Refactoring]</font><br/> 我們將這樣的概念稍微把他物件化，讓它可以重複被使用，而且增加一些保護措施。<br/> <blockquote>function showResponse(origReq) {<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var nav = $(this.nav.contentID);<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var last = nav.lastChild;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (last.nodeName != 'DIV') {<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last = last.previousSibling;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nav.removeChild (last);<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nav.innerHTML += origReq.responseText;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nav.innerHTML += '&lt;div style="background: #AAAAAA;"&gt;Fetching ... &lt;/div&gt;';<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.fetching = false;<br/> }<br/> <br/> function ScrollNav(contentID, url) {<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.contentID = contentID;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.contentObj = $(contentID);<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.contentObj.nav = this;&nbsp; // 記錄目前物件，給 checkScroll 函式使用<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.fetching = false;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.scrollTop = this.contentObj.scrollTop; // 記錄一開始 scrollTop<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.scrollHeight = this.contentObj.scrollHeight; // 記錄一開始 scrollHeight<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.url = url;<br/> <br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.idx = 0; // page number<br/> <br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.checkScroll = function() {<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(this.nav.scrollTop == this.scrollTop)<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this.fetching)<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br/> <br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.nav.scrollTop = this.scrollTop;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this.scrollHeight == parseInt(this.style.height) + this.scrollTop) {<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var opts = new Object;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; opts.parameters = 'page=' + this.nav.idx;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; opts.onComplete = showResponse.bind(this);<br/> <br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var ajax = new Ajax.Request(this.nav.url, opts);<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.fetching = true;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.nav.idx ++;<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br/> <br/> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // 攔截 onscroll event<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.contentObj.onscroll = this.checkScroll;<br/> }<br/> <br/> function init() {<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var nav = new ScrollNav('content', 'scroll_test.php');<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var nav = new ScrollNav('content2', 'scroll_test2.php');<br/> }<br/> </blockquote><br/> 這裡頭有個 ScrollNav 物件，就是將這些東西都包進去了，此外，於 checkScroll 函式中會檢查 event 是否被重複攔截，以及檢查目前 scrollbar 是否被拉動至最下方，唯有 scrollbar 被拉到最下面時，我們才向伺服器要求更多的資料，避免頻寬資源的浪費。scrollTop 跟 scrollHeight 都是內建的屬性，scrollTop 代表目前顯示的 view 距離最上方多少有 pixel，而 scrollHeight 則代表內容 view 的總長，同樣是 pixel，當妳資料越塞越多時，scrollTop 跟 scrollHeight 都會跟著增加，如果要判斷 scrollbar 是否為拉到最下方，最簡單的方法便是計算 scrollTop 和 DIV 區塊的高度總長是否等於 scrollHeight 即可。<br/> <br/> 至於在 showResponse() 函式中，我們會在每次抓到的新資料中都塞進個「Fetching ...」的字眼，代表目前正在抓取更多資料，這是一種小技巧，就像在大部分的 AJAX Pattern 中都可以看到的 Loading 字眼，妳也可以用個 gif 動畫來取代，只不過每次取得新資料時，必須將上一個「Fetching ...」移除。<br/> <br/> 想看結果嗎？請看 <a href="http://gais4.cs.ccu.edu.tw/%7Esys89/scroll.html" title="Demo">Demo</a> 。裡頭有兩個 DIV 區塊，左邊的 DIV 區塊所 request 的 PHP 檔執行較快，而右邊的每次都會 sleep 5 秒鐘，所以感覺起來比較慢，拉動兩個 scrollbar 妳便可以發覺兩者間的不同。<br/> <br/> <font size="3"><span style="FONT-WEIGHT:bold">[其他問題？]</span></font><br/> 目前這個範例還有些存在性的問題：<br/> <ol> <li> 別吃光 browser 的記憶體了。塞資料時要設立停止點，別一直狂塞，吃光妳瀏覽器的記憶體了。</li> <li> 不一定要拉動到最下方才開始抓取資料，可以在使用者的 scrollbar 接近最下方時，便向伺服器要求新資料，可以達到更順暢的操作。<br/></li> </ol> <br/> <br/> <font size="3"><span style="FONT-WEIGHT:bold">[這可以應用在哪？]</span></font>< br/> 我想這些概念，實作都是很簡單，重要的是妳有沒有創意，有沒有想到這些 idea，以及怎麼應用在妳的網頁中，這我想應該讓妳自己去想想看，不過我覺得可以應用在某些功能上，例如 blog 留言版，留言版並不是每個人都想看，如果留言眾多時，每次都將留言塞到使用者的瀏覽器上也不甚合理，如果透過類似的方法，先讓使用者看到最新的留言，如果想繼續看下去，只需要拉動 scrollbar 即可。應該還可以想出更多有趣的應用，不過還是大家自己想想看吧。<br/>  <br/>  <br/>  <br/>  <br/> </div>

]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6574505</link>
  <category>Programming</category>
  <pubDate>Mon, 16 Oct 2006 21:22:58 +0800</pubDate>
</item>
<item>
  <title>[Rails 筆記] Boolean pitfall</title>
  <description>
Ruby 沒有明確的 boolean 型別定義，不過通常以 nil 或 false 來代表 false，其他通通都是 true ，所以有個陷阱了，C 語言同樣也沒有 boolean 型別，但可以用 0 代表 false，非 0 代表 true，我們也都習以為常，不過在 Ruby 中，0 代表 true，例如：&lt;br&gt;
&lt;br&gt;
a = 0&lt;br&gt;
if (a) &lt;br&gt;
&lt;div style=&quot;padding-left:10px&quot;&gt;puts (&quot;true&quot;)&lt;/div&gt;
else&lt;br&gt;
&lt;div style=&quot;padding-left:10px&quot;&gt;puts (&quot;false&quot;)&lt;/div&gt;
end&lt;br&gt;
&lt;br&gt;
會印什麼，true 啊。&lt;br&gt;

   </description>

<content:encoded><![CDATA[
Ruby 沒有明確的 boolean 型別定義，不過通常以 nil 或 false 來代表 false，其他通通都是 true ，所以有個陷阱了，C 語言同樣也沒有 boolean 型別，但可以用 0 代表 false，非 0 代表 true，我們也都習以為常，不過在 Ruby 中，0 代表 true，例如：<br>
<br>
a = 0<br>
if (a) <br>
<div style="padding-left:10px">puts ("true")</div>
else<br>
<div style="padding-left:10px">puts ("false")</div>
end<br>
<br>
會印什麼，true 啊。<br>

]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6505719</link>
  <category>Programming</category>
  <pubDate>Mon, 02 Oct 2006 10:47:39 +0800</pubDate>
</item>
<item>
  <title>[Rails 筆記] 在 session 中儲存物件</title>
  <description>
答案是利用 Ruby 的 Marshal 物件，如下例：&lt;br&gt;&lt;br&gt;&lt;blockquote&gt;class AdminController &lt; ApplicationController&lt;br&gt;    def do_login&lt;br&gt;        if request.post?&lt;br&gt;            user = User.login(params[:uid], params[:pwd])&lt;br&gt;           if (user)&lt;br&gt;                session[:user] = Marshal.dump(user)&lt;br&gt;            end&lt;br&gt;        end&lt;br&gt;    end&lt;br&gt;end&lt;br&gt;&lt;/blockquote&gt;&lt;br&gt;然後在 application.rb 中：&lt;br&gt;&lt;br&gt;&lt;blockquote&gt;class ApplicationController &lt; ActionController::Base&lt;br&gt;    model :user&lt;br&gt;    def setup_variables&lt;br&gt;        if (session[:user])&lt;br&gt;            @login_user=Marshal.load(session[:user])&lt;br&gt;        end&lt;br&gt;    end&lt;br&gt;end&lt;br&gt;&lt;/blockquote&gt;這樣有什麼好處，好處是對於一些常用的物件，例如 Query DB 得到的 Model，我不用在每個 page 都再去 query database，將他記錄在 session 中即可，而且可以避免 db schema 更改後還要改 code 的窘境。&lt;br&gt;&lt;br&gt;&lt;br&gt;
   </description>

<content:encoded><![CDATA[
答案是利用 Ruby 的 Marshal 物件，如下例：<br><br><blockquote>class AdminController < ApplicationController<br>    def do_login<br>        if request.post?<br>            user = User.login(params[:uid], params[:pwd])<br>           if (user)<br>                session[:user] = Marshal.dump(user)<br>            end<br>        end<br>    end<br>end<br></blockquote><br>然後在 application.rb 中：<br><br><blockquote>class ApplicationController < ActionController::Base<br>    model :user<br>    def setup_variables<br>        if (session[:user])<br>            @login_user=Marshal.load(session[:user])<br>        end<br>    end<br>end<br></blockquote>這樣有什麼好處，好處是對於一些常用的物件，例如 Query DB 得到的 Model，我不用在每個 page 都再去 query database，將他記錄在 session 中即可，而且可以避免 db schema 更改後還要改 code 的窘境。<br><br><br>
]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6490786</link>
  <category>Programming</category>
  <pubDate>Thu, 28 Sep 2006 00:27:19 +0800</pubDate>
</item>
<item>
  <title>[Rails 筆記] ActiveRecord 轉換 JSON</title>
  <description>
酷耶，看到這都快興奮的跳到桌子上了，看看這個連結吧：&lt;a href=&quot;http://www.bigbold.com/snippets/posts/show/474&quot; target=_&gt;Accessing ActiveRecord objects in javascript &lt;/a&gt;&lt;br /&gt;
雖然我看不太懂這段 code 的意思，不過測試的結果，可以 work 耶！ 讚！&lt;br /&gt;
就只剩下 JSON 轉 ActiveRecord 了，改天再來研究看看。&lt;br /&gt;
&lt;br /&gt;
(1) 安裝 json:&lt;br /&gt;
&lt;u&gt; % gem install json&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
(2) Add a new file : /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/json.rb , 裡頭包含以下程式碼：&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
require &#039;json/lexer&#039;&lt;br /&gt;
require &#039;json/objects&#039;&lt;br /&gt;
module ActiveRecord&lt;br /&gt;
&amp;nbsp;&amp;nbsp;module Json # :nodoc:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DEFAULT_CONVERSIONS = { Time =&gt; [:to_s, :db] }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def to_json(conversions = {})&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conversions = DEFAULT_CONVERSIONS.merge(conversions)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.attributes.keys.inject({}) do |hsh, key|&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;value = self.send(key)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hsh.merge(key =&gt; conversions[value.class] ? value.send(*conversions[value.class]) : value.to_s)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end.to_json&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;
&amp;nbsp;&amp;nbsp;end&lt;br /&gt;
end&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
(3) 在 environment.rb 中加上： &lt;font color=&quot;red&quot;&gt;[Update]: 似乎不用加以下這段，加了反讓 fastcgi 掛掉，不加也能 work 啦&lt;/font&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
require &quot;#{RAILS_ROOT}/lib/active_record/json&quot;&lt;br /&gt;
ActiveRecord::Base.class_eval { include ActiveRecord::Json }&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
(4) 使用時，呼叫 to_json() 函式即可。&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
user = User.new()&lt;br /&gt;
user.to_json()&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;

   </description>

<content:encoded><![CDATA[
酷耶，看到這都快興奮的跳到桌子上了，看看這個連結吧：<a href="http://www.bigbold.com/snippets/posts/show/474" target=_>Accessing ActiveRecord objects in javascript </a><br />
雖然我看不太懂這段 code 的意思，不過測試的結果，可以 work 耶！ 讚！<br />
就只剩下 JSON 轉 ActiveRecord 了，改天再來研究看看。<br />
<br />
(1) 安裝 json:<br />
<u> % gem install json</u><br />
<br />
(2) Add a new file : /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/json.rb , 裡頭包含以下程式碼：<br />
<blockquote><br />
require 'json/lexer'<br />
require 'json/objects'<br />
module ActiveRecord<br />
&nbsp;&nbsp;module Json # :nodoc:<br />
&nbsp;&nbsp;&nbsp;&nbsp;DEFAULT_CONVERSIONS = { Time => [:to_s, :db] }<br />
&nbsp;&nbsp;&nbsp;&nbsp;def to_json(conversions = {})<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conversions = DEFAULT_CONVERSIONS.merge(conversions)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.attributes.keys.inject({}) do |hsh, key|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value = self.send(key)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hsh.merge(key => conversions[value.class] ? value.send(*conversions[value.class]) : value.to_s)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end.to_json<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
end<br />
</blockquote><br />
<br />
(3) 在 environment.rb 中加上： <font color="red">[Update]: 似乎不用加以下這段，加了反讓 fastcgi 掛掉，不加也能 work 啦</font><br />
<blockquote><br />
require "#{RAILS_ROOT}/lib/active_record/json"<br />
ActiveRecord::Base.class_eval { include ActiveRecord::Json }<br />
</blockquote><br />
<br />
(4) 使用時，呼叫 to_json() 函式即可。<br />
<blockquote><br />
user = User.new()<br />
user.to_json()<br />
</blockquote><br />
<br />

]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6482276</link>
  <category>Programming</category>
  <pubDate>Mon, 25 Sep 2006 18:59:59 +0800</pubDate>
</item>
<item>
  <title>[Rails 筆記] 如何使用 Stored Procedure (MySQL)</title>
  <description>
儘管 Rails 的原始作者之一 David Heinemeier 對 Database 的 Stored Procedure 並&lt;a href=&quot;http://dev.mysql.com/tech-resources/interviews/david-heinemeier-hansson-rails.html&quot; target=_&gt;不太感興趣&lt;/a&gt;，都有了 Active Record 了，何需 Stored Procedure，不過需求總是存在的，要改好像也不太難，這篇筆記都是參考自 - &lt;a href=&quot;http://guyharrison.typepad.com/guy_harrisons_blog/2006/04/mysql_stored_pr.html&quot; target=_&gt;MySQL stored procedures with Ruby&lt;/a&gt; 以及 &lt;a href=&quot;http://wiki.rubyonrails.org/rails/pages/StoredProceduresInMySql&quot; target=_&gt;StoredProceduresInMySql&lt;/a&gt;。這各式兩種作法，一種是改 Rails 原本的程式碼，另外一種則是改自己的程式碼 ，各有優缺點。&lt;br /&gt;
&lt;br /&gt;
先看改 Rails 的方法：&lt;br /&gt;
(1) 找到 Rails 中的 mysql_adapter.rb 檔，他通常位於：&lt;br /&gt;
&lt;u&gt;&lt;i&gt;/usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/connection_adapters/mysql_adapter.rb&lt;/i&gt;&lt;/u&gt;&lt;br /&gt;
(2) 修改底下這行：&lt;br /&gt;
&lt;u&gt;&lt;i&gt;ConnectionAdapters::MysqlAdapter.new( mysql, logger, [host, username, password, database, port, socket], config)&lt;/i&gt;&lt;/u&gt;&lt;br /&gt;
把它改成：&lt;br /&gt;
&lt;u&gt;&lt;i&gt;ConnectionAdapters::MysqlAdapter.new( mysql, logger, [host, username, password, database, port, socket&lt;font color=&quot;red&quot;&gt;&lt;b&gt;, Mysql::CLIENT_MULTI_RESULTS&lt;/b&gt;&lt;/font&gt;], config)&lt;/i&gt;&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
(3) 新增加一個 function:&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
def select_sp(sql, name = nil)&lt;br /&gt;
&amp;nbsp;rows = select(sql, name = nil)&lt;br /&gt;
&amp;nbsp;while (@connection.more_results?())&lt;br /&gt;
&amp;nbsp;&amp;nbsp;@connection.next_result()&lt;br /&gt;
&amp;nbsp;end        &lt;br /&gt;
&amp;nbsp;return rows&lt;br /&gt;
end&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
(4) 使用上，如下例：&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
connection.select_sp (&quot;CALL my_stored_proc();&quot;)&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
如果妳不想改 code，就不能用 Rails 的 adapter ，而是要自己 connect。&lt;br /&gt;

   </description>

<content:encoded><![CDATA[
儘管 Rails 的原始作者之一 David Heinemeier 對 Database 的 Stored Procedure 並<a href="http://dev.mysql.com/tech-resources/interviews/david-heinemeier-hansson-rails.html" target=_>不太感興趣</a>，都有了 Active Record 了，何需 Stored Procedure，不過需求總是存在的，要改好像也不太難，這篇筆記都是參考自 - <a href="http://guyharrison.typepad.com/guy_harrisons_blog/2006/04/mysql_stored_pr.html" target=_>MySQL stored procedures with Ruby</a> 以及 <a href="http://wiki.rubyonrails.org/rails/pages/StoredProceduresInMySql" target=_>StoredProceduresInMySql</a>。這各式兩種作法，一種是改 Rails 原本的程式碼，另外一種則是改自己的程式碼 ，各有優缺點。<br />
<br />
先看改 Rails 的方法：<br />
(1) 找到 Rails 中的 mysql_adapter.rb 檔，他通常位於：<br />
<u><i>/usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/connection_adapters/mysql_adapter.rb</i></u><br />
(2) 修改底下這行：<br />
<u><i>ConnectionAdapters::MysqlAdapter.new( mysql, logger, [host, username, password, database, port, socket], config)</i></u><br />
把它改成：<br />
<u><i>ConnectionAdapters::MysqlAdapter.new( mysql, logger, [host, username, password, database, port, socket<font color="red"><b>, Mysql::CLIENT_MULTI_RESULTS</b></font>], config)</i></u><br />
<br />
(3) 新增加一個 function:<br />
<blockquote><br />
def select_sp(sql, name = nil)<br />
&nbsp;rows = select(sql, name = nil)<br />
&nbsp;while (@connection.more_results?())<br />
&nbsp;&nbsp;@connection.next_result()<br />
&nbsp;end        <br />
&nbsp;return rows<br />
end<br />
</blockquote><br />
<br />
(4) 使用上，如下例：<br />
<blockquote><br />
connection.select_sp ("CALL my_stored_proc();")<br />
</blockquote><br />
<br />
如果妳不想改 code，就不能用 Rails 的 adapter ，而是要自己 connect。<br />

]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6482125</link>
  <category>Programming</category>
  <pubDate>Mon, 25 Sep 2006 18:22:21 +0800</pubDate>
</item>
<item>
  <title>[Rails 筆記] Rails Localization</title>
  <description>
Rails app 怎麼做 localization ? 好問題！ 已經有人 port UNIX 上的 gettext 到 ruby 上，並有文件介紹如何與 Rails app 整合。&lt;br&gt;&lt;br&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;[安裝]&lt;/span&gt;&lt;br&gt;確認你有安裝 gettext，在 Ubuntu 上請用以下命令安裝：&lt;br&gt;&lt;br&gt;    &lt;span style=&quot;font-style: italic; text-decoration: underline;&quot;&gt;% apt-get install gettext&lt;/span&gt;&lt;br&gt;&lt;br&gt;安裝 &lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;libgettext-ruby1.8:&lt;/span&gt;&lt;br style=&quot;font-family: Verdana;&quot;&gt;&lt;br style=&quot;font-family: Verdana;&quot;&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;    &lt;span style=&quot;font-style: italic; text-decoration: underline;&quot;&gt;% gem install gettext&lt;/span&gt;&lt;br&gt;&lt;br&gt;或者&lt;br&gt;&lt;br&gt;    &lt;span style=&quot;font-style: italic; text-decoration: underline;&quot;&gt;% apt-get install &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;span style=&quot;font-style: italic; text-decoration: underline;&quot;&gt;libgettext-ruby1.8&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;[建立環境]&lt;/span&gt;&lt;br&gt;舉例來說，如果我的 Rails app 目錄位於 /var/rails/sandbox/ 路徑下，先在該目錄下建立 po 檔案夾，裡頭包含各個你要 localize 的語言子目錄，如下：&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;/code&gt;&lt;blockquote&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;% ls -l po&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;drwxr-xr-x 2 root root 4096 2006-09-15 20:21 en&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;drwxr-xr-x 2 root root 4096 2006-09-15 21:21 ja&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;drwxr-xr-x 2 root root 4096 2006-09-15 20:21 zh_CN&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;drwxr-xr-x 2 root root 4096 2006-09-15 21:04 zh_TW&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;br&gt;編寫 Rakefile，如下：&lt;br&gt;&lt;/span&gt;&lt;/code&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;blockquote&gt;require(File.join(File.dirname(__FILE__), &#039;config&#039;, &#039;boot&#039;))&lt;br&gt;&lt;br&gt;require &#039;rake&#039;&lt;br&gt;require &#039;rake/testtask&#039;&lt;br&gt;require &#039;rake/rdoctask&#039;&lt;br&gt;&lt;br&gt;require &#039;tasks/rails&#039;&lt;br&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;require &#039;gettext/utils&#039;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;desc &quot;Update pot/po files&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;task :updatepo do&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;  MY_APP_TEXT_DOMAIN = &quot;sandbox&quot;   #sandbox 是我的 Textdomain, 你應該改成你自己的&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;  MY_APP_VERSION     = &quot;sandbox 0.0.9&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;  GetText.update_pofiles(MY_APP_TEXT_DOMAIN,&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                          Dir.glob(&quot;{app,lib}/**/*.{rb,rhtml}&quot;),&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                          MY_APP_VERSION)&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;end&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;desc &quot;Create mo-files&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;task :makemo do&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;  GetText.create_mofiles(true, &quot;po&quot;, &quot;locale&quot;)&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;end&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;br&gt;&lt;/blockquote&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;[攥寫你的程式碼]&lt;/span&gt;&lt;br&gt;你想要做 localize 的地方可以利用 _() 或者 N_() 函式包裝起來，如下：&lt;br&gt;&lt;/span&gt;&lt;/code&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;blockquote&gt;&lt;h2&gt;&lt;%= _(&quot;This string should be localized&quot;) %&gt;&lt;/h2&gt;&lt;br&gt;&lt;h2&gt;&lt;%= N_(&quot;This string should be localized&quot;) %&gt;&lt;/h2&gt;&lt;br&gt;&lt;/blockquote&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;設定 application.rb，如下：&lt;br&gt;&lt;/span&gt;&lt;/code&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;blockquote&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;require &#039;gettext/rails&#039;&lt;/span&gt;&lt;br&gt;class ApplicationController &lt; ActionController::Base&lt;br&gt;        &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;GetText.locale = &quot;zh_TW&quot;&lt;/span&gt;&lt;br&gt;        &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;init_gettext &quot;sandbox&quot;&lt;/span&gt;&lt;br&gt;&lt;/blockquote&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;在這裡我先暫時將 locale 強制設定成 zh_TW 做測試，事實上，你可以透過幾種方法來改變語言(如果不直接設定 GetText.locale= 的話)：&lt;br&gt;&lt;/span&gt;&lt;/code&gt;&lt;ul&gt;&lt;li&gt;QUERY_STRING 中的 lang 參數設定。&lt;/li&gt;&lt;li&gt;Cookie 中的 lang 參數設定。&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;HTTP_ACCEPT_LANGUAGE&lt;/span&gt; 中的值。&lt;/code&gt;&lt;/li&gt;&lt;li&gt;你也可以透過 config/routes.rb 讓某路徑對應到特定語言中，例如 /login/zh_TW/hello/ 可以對應到 zh_TW 語言中。&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;ActionController::Routing::Routes.draw do |map|&lt;br&gt;    &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;map.connect &#039;:controller/:lang/:action/:id&#039;&lt;/span&gt;&lt;br&gt;end&lt;br&gt;&lt;/blockquote&gt;&lt;code&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;br&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;[建立 po 跟 mo 檔]&lt;/span&gt;&lt;br&gt;回到你的 Rails Root 路徑下，執行以下命令產生 pot 檔。&lt;br&gt;&lt;br&gt;    &lt;span style=&quot;font-style: italic; text-decoration: underline;&quot;&gt;% rake updatepo&lt;/span&gt;&lt;br&gt;&lt;br&gt;執行完後你會在 po/ 目錄下找到一份 pot 檔，檔名是你取的 Textdomain，將這份 pot 檔案翻譯後並改名成附檔名為 .po 的檔案，並放到該語言的目錄下，例如你翻譯成中文後，可以放到 zh_TW 目錄下。&lt;br&gt;&lt;br&gt;翻譯完後，執行：&lt;br&gt;&lt;br&gt;    &lt;span style=&quot;font-style: italic; text-decoration: underline;&quot;&gt;% rake makemo&lt;/span&gt;&lt;br&gt;&lt;br&gt;你會發現在你 Rails app ROOT 目錄下會多個檔案夾 - locale ，在裡頭你會發現 zh_TW/LC_MESSAGES/sandbox.mo ，這就是產生的 mo 檔，有用過 gettext 的人，相信對這些流程應該不陌生。&lt;br&gt;執行你的 Rails app 後，你就可以發現你的字串都被置換了。&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;[參考資源]&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;/code&gt;&lt;ul&gt;&lt;li&gt;&lt;a title=&quot;Ruby-Gettext-Package&quot; target=&quot;blank_&quot; href=&quot;http://www.yotabanana.com/hiki/ruby-gettext.html?ruby-gettext&quot;&gt;Ruby-Gettext-Package&lt;/a&gt; &lt;/li&gt;&lt;li&gt;&lt;a title=&quot;Using Gettext To Translate Your Rails Application&quot; target=&quot;blank_&quot; href=&quot;http://manuals.rubyonrails.com/read/chapter/105&quot;&gt;Using Gettext To Translate Your Rails Application&lt;/a&gt;  (y) &lt;/li&gt;&lt;li&gt;&lt;a title=&quot;Ruby-GetText-Package HOWTO for Ruby on Rails&quot; target=&quot;blank_&quot; href=&quot;http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html&quot;&gt;Ruby-GetText-Package HOWTO for Ruby on Rails&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
   </description>

<content:encoded><![CDATA[
Rails app 怎麼做 localization ? 好問題！ 已經有人 port UNIX 上的 gettext 到 ruby 上，並有文件介紹如何與 Rails app 整合。<br><br><span style="font-weight: bold;">[安裝]</span><br>確認你有安裝 gettext，在 Ubuntu 上請用以下命令安裝：<br><br>    <span style="font-style: italic; text-decoration: underline;">% apt-get install gettext</span><br><br>安裝 <code><span style="font-family: Verdana;">libgettext-ruby1.8:</span><br style="font-family: Verdana;"><br style="font-family: Verdana;"><span style="font-family: Verdana;">    <span style="font-style: italic; text-decoration: underline;">% gem install gettext</span><br><br>或者<br><br>    <span style="font-style: italic; text-decoration: underline;">% apt-get install </span></span></code><code><span style="font-family: Verdana;"><span style="font-style: italic; text-decoration: underline;">libgettext-ruby1.8</span><br><br><span style="font-weight: bold;">[建立環境]</span><br>舉例來說，如果我的 Rails app 目錄位於 /var/rails/sandbox/ 路徑下，先在該目錄下建立 po 檔案夾，裡頭包含各個你要 localize 的語言子目錄，如下：<br><br></span></code><blockquote><code><span style="font-family: Verdana;">% ls -l po</span></code><br><code><span style="font-family: Verdana;">drwxr-xr-x 2 root root 4096 2006-09-15 20:21 en</span></code><br><code><span style="font-family: Verdana;">drwxr-xr-x 2 root root 4096 2006-09-15 21:21 ja</span></code><br><code><span style="font-family: Verdana;">drwxr-xr-x 2 root root 4096 2006-09-15 20:21 zh_CN</span></code><br><code><span style="font-family: Verdana;">drwxr-xr-x 2 root root 4096 2006-09-15 21:04 zh_TW</span></code><br><code><span style="font-family: Verdana;"></span></code></blockquote><code><span style="font-family: Verdana;"><br>編寫 Rakefile，如下：<br></span></code><code><span style="font-family: Verdana;"></span></code><blockquote>require(File.join(File.dirname(__FILE__), 'config', 'boot'))<br><br>require 'rake'<br>require 'rake/testtask'<br>require 'rake/rdoctask'<br><br>require 'tasks/rails'<br><span style="color: rgb(255, 0, 0);">require 'gettext/utils'</span><br><br><span style="color: rgb(255, 0, 0);">desc "Update pot/po files"</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">task :updatepo do</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">  MY_APP_TEXT_DOMAIN = "sandbox"   #sandbox 是我的 Textdomain, 你應該改成你自己的</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">  MY_APP_VERSION     = "sandbox 0.0.9"</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">  GetText.update_pofiles(MY_APP_TEXT_DOMAIN,</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">                          Dir.glob("{app,lib}/**/*.{rb,rhtml}"),</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">                          MY_APP_VERSION)</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">end</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">desc "Create mo-files"</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">task :makemo do</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">  GetText.create_mofiles(true, "po", "locale")</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">end</span><br style="color: rgb(255, 0, 0);"><br></blockquote><code><span style="font-family: Verdana;"><span style="font-weight: bold;">[攥寫你的程式碼]</span><br>你想要做 localize 的地方可以利用 _() 或者 N_() 函式包裝起來，如下：<br></span></code><code><span style="font-family: Verdana;"></span></code><blockquote><h2><%= _("This string should be localized") %></h2><br><h2><%= N_("This string should be localized") %></h2><br></blockquote><code><span style="font-family: Verdana;">設定 application.rb，如下：<br></span></code><code><span style="font-family: Verdana;"></span></code><blockquote><span style="color: rgb(255, 0, 0);">require 'gettext/rails'</span><br>class ApplicationController < ActionController::Base<br>        <span style="color: rgb(255, 0, 0);">GetText.locale = "zh_TW"</span><br>        <span style="color: rgb(255, 0, 0);">init_gettext "sandbox"</span><br></blockquote><code><span style="font-family: Verdana;">在這裡我先暫時將 locale 強制設定成 zh_TW 做測試，事實上，你可以透過幾種方法來改變語言(如果不直接設定 GetText.locale= 的話)：<br></span></code><ul><li>QUERY_STRING 中的 lang 參數設定。</li><li>Cookie 中的 lang 參數設定。</li><li><code><span style="font-family: Verdana;">HTTP_ACCEPT_LANGUAGE</span> 中的值。</code></li><li>你也可以透過 config/routes.rb 讓某路徑對應到特定語言中，例如 /login/zh_TW/hello/ 可以對應到 zh_TW 語言中。</li></ul><blockquote>ActionController::Routing::Routes.draw do |map|<br>    <span style="color: rgb(255, 0, 0);">map.connect ':controller/:lang/:action/:id'</span><br>end<br></blockquote><code><span style="font-family: Verdana;"><br><span style="font-weight: bold;">[建立 po 跟 mo 檔]</span><br>回到你的 Rails Root 路徑下，執行以下命令產生 pot 檔。<br><br>    <span style="font-style: italic; text-decoration: underline;">% rake updatepo</span><br><br>執行完後你會在 po/ 目錄下找到一份 pot 檔，檔名是你取的 Textdomain，將這份 pot 檔案翻譯後並改名成附檔名為 .po 的檔案，並放到該語言的目錄下，例如你翻譯成中文後，可以放到 zh_TW 目錄下。<br><br>翻譯完後，執行：<br><br>    <span style="font-style: italic; text-decoration: underline;">% rake makemo</span><br><br>你會發現在你 Rails app ROOT 目錄下會多個檔案夾 - locale ，在裡頭你會發現 zh_TW/LC_MESSAGES/sandbox.mo ，這就是產生的 mo 檔，有用過 gettext 的人，相信對這些流程應該不陌生。<br>執行你的 Rails app 後，你就可以發現你的字串都被置換了。<br><br><br><span style="font-weight: bold;">[參考資源]</span><br></span></code><ul><li><a title="Ruby-Gettext-Package" target="blank_" href="http://www.yotabanana.com/hiki/ruby-gettext.html?ruby-gettext">Ruby-Gettext-Package</a> </li><li><a title="Using Gettext To Translate Your Rails Application" target="blank_" href="http://manuals.rubyonrails.com/read/chapter/105">Using Gettext To Translate Your Rails Application</a>  (y) </li><li><a title="Ruby-GetText-Package HOWTO for Ruby on Rails" target="blank_" href="http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html">Ruby-GetText-Package HOWTO for Ruby on Rails</a> </li></ul><br><br><br>
]]>
</content:encoded>


  <link>http://blog.yam.com/syshen/article/6447407</link>
  <category>Programming</category>
  <pubDate>Fri, 15 Sep 2006 21:54:18 +0800</pubDate>
</item>
</channel>
</rss>