tag:blogger.com,1999:blog-57057674168914748832024-02-19T11:09:31.663+08:00貓桑觀察誌貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.comBlogger102125tag:blogger.com,1999:blog-5705767416891474883.post-4673091825910571652015-11-03T13:43:00.004+08:002015-11-03T13:47:19.214+08:00[轉載] 為什麼分紅費用化對員工不好呢?查資料時看到看到的,蠻好的解釋了分紅費用化的狀況。<br>
<br>
重點:<br>
<br>
<ol>
<li>過去股票紅利是照面額計算 (Ex. 分紅10萬,相當10張股票,但是股票市值往往遠超過面額)</li>
<li>依據上一點,「面額」及「市值」之間的成本便由小股東承擔了,也造成每股盈餘不明的情況</li>
<li>費用化後,因員工配股張數是以「分紅金額」除以前一年最後交易日的股價</li>
</ol>
<br>
<br>
<a href="http://cat-son.blogspot.com/2015/11/blog-post.html#more">閱讀更多 »</a><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-21073930861342331902015-03-17T01:09:00.000+08:002015-03-17T01:09:07.768+08:00如何寫出 User Story<br>
<h3>
什麼是 User Story?</h3>
User Story 是一段簡單的功能敘述,以 <b>客戶或使用者的觀點 </b>撰寫下有價值的功能(functionality/feature)。與其說它是規格文件(documentation),不如說它代表(represent)客戶的一個需求而已,因為實做細節將延後至開發時才會確定。<br>
<br>
幾個 User Stories 的範例如下:<br>
<br>
<ul>
<li>使用者可以在網站上張貼履歷</li>
<li>使用者可以搜尋有哪些工作</li>
<li>公司可以張貼新工作</li>
<li>使用者可以限制誰可以看到他的履歷</li>
</ul>
<br>
<br>
<a href="http://cat-son.blogspot.com/2015/03/user-story.html#more">閱讀更多 »</a><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com2tag:blogger.com,1999:blog-5705767416891474883.post-82872235075156197692015-02-18T20:13:00.000+08:002015-03-16T20:00:51.274+08:00Deferred 與 Promise 的差異<br>
在談Promise 之前,我們先來了解一下 CommonJS.org<br>
<br>
<h3>
CommonJS.org</h3>
CommonJS 是一個致力於將 JavaScript 生態圈標準化的計畫,尤其是針對瀏覽器以外的應用環境,也因此第一個版本的名字叫做 ServerJS。 <br>
CommonJS 的終極目標是制定一個像 C++ 標準庫一樣的規範,也就是<span style="color: red;"><b>介面</b></span>,使得基於 CommonJS API 的應用程序可以在不同的環境下運行,就像用 C++ 編寫的應用程序可以使用不同的編譯器和運行時函數庫一樣。為了保持中立,CommonJS 不參與函式庫的實作,而是交給像 Node.js 之類的項目來完成。<br>
<br>
而不少開發者向 CommonJS 提出 Promise 的規範草案,但是一直未被列入正式規範,有著 Promises/A, B, KISS, C, D 等版本。其中以 Promises/A 的提案最為簡單,也最常被大家提及。<br>
<br>
值得一提的是:Promise/B, D 的提案人是知名流程控管套件 <a href="https://github.com/kriskowal/q" target="_blank">Q.js</a> 的作者 Kris Kowal<br>
<blockquote class="tr_bq">
滿有趣的一點是:Node 團隊在前年左右放棄繼續遵守 CommonJS 的規範。Isaac 指出 "Ryan basically always <b>gave zero fucks about CommonJS</b> anyway" ,並轉述了 Ryan 的一句重話 : <b>"Forget CommonJS. It's dead. <span style="color: red;">We are server side JavaScript</span>."</b><br>
有興趣可以看看這個Github的討論串:<a href="https://github.com/joyent/node/issues/5132#issuecomment-15432598" target="_blank">https://github.com/joyent/node/issues/5132#issuecomment-15432598</a><br>
( <a href="https://github.com/isaacs" target="_blank">Issac</a> 是 NPM 的作者, <a href="https://github.com/ry" target="_blank">Ryan</a> 是 Node 之父 )</blockquote>
<br>
<a href="http://cat-son.blogspot.com/2015/02/deferred-promise.html#more">閱讀更多 »</a><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com1tag:blogger.com,1999:blog-5705767416891474883.post-1532039764413306702015-02-04T16:12:00.000+08:002015-02-05T21:35:04.613+08:00你還在為了UI-binding使用肥肥的Angular嗎?試試這些前端函式庫吧!<h3>
<b><span style="font-weight: normal;">從 jQuery 到 Angular</span></b></h3>
從最早的 jQuery 以後,各種前端framework百花齊放:Backbone, Knockout, Ember, Angular....<br>
其中 Angular 狹著 Google 的大名,可以說是在前端世界中呼風喚雨,但是許多人使用Anugular一段時間以後才發現入門容易但是深入難,而且隨著專案的複雜性增加,也開始踩到了各種地雷。因此也有人用這張圖來揶揄模擬Angular的學習曲線:<br>
<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNgO0P8tBUTYxQdYYHTV0iLAVl_bqplcGrApRvknqn-fVcDUn2HIMiNF3aFGiejTesHAD7rFU3pfi87VX7UH4crgYSYsz3TD56s1bsnRnzymekQqV6es77s1DWYT8MJ4bqKlLvTa4EgGro/s1600/js-learning-curves.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNgO0P8tBUTYxQdYYHTV0iLAVl_bqplcGrApRvknqn-fVcDUn2HIMiNF3aFGiejTesHAD7rFU3pfi87VX7UH4crgYSYsz3TD56s1bsnRnzymekQqV6es77s1DWYT8MJ4bqKlLvTa4EgGro/s1600/js-learning-curves.jpeg" height="168" width="400"></a></div>
<br>
<br>
<h3>
<b><span style="font-weight: normal;">UI only</span></b></h3>
許多人開始發現,很多狀態下他們幾乎只需要 Data-UI binding 的功能,React.js 這個 facebook 御用、注重高效render 的 Library 就開始受到廣大的目光關注... React不是個完整的framework,只是專注於View的Library,因此更輕量、也更能與其他framework整合、相容。React官網是這麼說的:<br>
<blockquote class="tr_bq">
<b>Just the UI</b><br>
Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it's easy to try it out on a small feature in an existing project.</blockquote>
<br>
<br>
<b><span style="font-size: large;">但是!</span></b><br>
<br>
React 推薦使用 <a href="http://jsx.github.io/" target="_blank">JSX</a> 在程式碼中勾勒 template,這點我就真的不行了,覺得髒髒的。所以我實在無法接受 React。<br>
<br>
但是幸好這是一個前端技術大爆炸的時代,我們還有很多選擇....<br>
<br>
<br>
<a href="http://cat-son.blogspot.com/2015/02/ui-bindingangular.html#more">閱讀更多 »</a><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-82953625562866173682015-01-06T20:21:00.003+08:002015-01-06T20:21:40.099+08:00手機網頁必會技巧!HTML meta viewport 屬性<h3>
什麽是Viewport</h3>
手機瀏覽器是把頁面放在一個虛擬的「窗口」(viewport) 中,通常這個虛擬的「窗口」(viewport) 會比螢幕寬,這樣就不用把每個網頁擠到很小的窗口中(這樣會破壞沒有針對手機瀏覽器優化的網頁的布局),用戶可以通過平移和縮放來看網頁的不同部分。移動版的 Safari 瀏覽器最新引進了 viewport 這個 meta tag,讓網頁開發者來控制 viewport 的大小和縮放,其他手機瀏覽器也基本支持。舉例來說,一個常用於RWD優化過的頁面上,常會有這樣的程式碼:<br />
<pre><code>
<meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1″>
</code><span style="font-family: Heiti TC;"><span style="white-space: normal;">
</span></span></pre>
<br />
<br />
<h3>
Viewport的屬性</h3>
<br />
<ul>
<li>width:控制 viewport 的大小,可以指定的一個值,例如600或者其他的值,如 device-width 為設備的寬度(單位為縮放為 100% 時的 CSS 的像素)。</li>
<li>height:和 width 相對應,指定高度。</li>
<li>initial-scale:初始縮放比例,也即是當頁面第一次 load 的時候縮放比例。</li>
<li>maximum-scale:允許用戶縮放到的最大比例。</li>
<li>minimum-scale:允許用戶縮放到的最小比例。</li>
<li>user-scalable:用戶是否可以手動縮放</li>
</ul>
<br />
<br />
其中特別需要注意的是 width這個屬性,比較不容易搞懂。<br />
舉例來說,當你的頁面沒有經過RWD優化,最適合的解析度是960px寬,因此有些使用者拿著螢幕800像素寬的手機時,會無法看到右方160px的區塊,必須進行橫移或縮放。<br />
而你希望使用者無論拿著多大的手機,看到你的網頁時都能夠從左到右完整顯示的顯示網頁內容。於是你就需要設定width為960px,此時無論是480px, 640px, 800px 甚至是 1280px寬的手機,都會調整顯示比例至能完整顯示800px的寬度。<br />
當然,手機的解析度是不可能變的,於是小手機上看到的內容就會比較模糊不清,畢竟他是試圖使用480px來顯示960px的內容。<br />
<br />
<br />
<h3>
Reference:</h3>
穆乙's Blog: <a href="http://www.cnblogs.com/pigtail/archive/2013/03/15/2961631.html">http://www.cnblogs.com/pigtail/archive/2013/03/15/2961631.html</a><br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-31054669368563959622014-12-21T11:46:00.001+08:002014-12-21T11:47:18.090+08:00初探 Python Decorator最近剛巧聽到朋友介紹 Python 的 Decorator。<br />
一開始以為是指 design pattern,後來才發現原來是Pyhton特有的一種語法糖,其實有點合成函數的味道。<br />
<br />
舉例來說,有一個取得商品價錢的函式:<br />
<pre>
def get_price(product_id):
...
return price
</pre>
<br />
但是為了慶祝聖誕節,有的商品打八折,有的商品則是大打五折<br />
而該打幾折的程式是由另一個函式判斷:<br />
<pre>
def christmas_discount(func):
discount = get_discount()
def get_christmas_price(product_id):
return func(product_id) * discount
return get_christmas_price
</pre>
<br />
這時我們可以用這兩個程式合成一個新的程式:<br />
<pre>
get_price(21) // ==> 200
get_price = christmas_discount(get_price)
get_price(21) // ==> '160'
</pre>
<br />
但是我們可以用 decorator語法糖「掛上」合成的函式:<br />
<pre>
@christmas_discount
def get_price(product_id):
...
return price
get_price(21) // ==> '160'
</pre>
<br />
<h3>
Functional Programming vs OOP:</h3>
在OOP中也有所謂的裝飾者模式,具體的講解可以參考 <a href="http://openhome.cc/Gossip/DesignPattern/DecoratorPattern.htm" target="_blank">良葛格的文章</a><br />
這裡就可以看出:原本許多在OOP需要特別實作的設計模式,在Python或JavaScript等函數式語言中都能夠很直觀、輕鬆的被實作出來。<br />
常見的Factory模式也是一樣的道理,在JS中能夠被輕易的實作。<div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-91738520949506012272014-12-19T00:31:00.002+08:002014-12-19T11:45:44.204+08:00Git 小筆記跟 git 太不熟了,在這邊堆放一些常用筆記<br />
<br />
<h3>
Branch:</h3>
git branch //看local branch(星號代表現在所在的branch)<br />
git branch <bar> // 新增 "bar" branch<br />
git branch -D <foo> // 刪除 "foo" branch<br />
<br />
<br />
<h3>
Checkout:</h3>
git checkout <bar> // 切換到 local 的 "bar" branch<br />
git checkout -b <NewBranch> // 新創一個 branch 並同時 checkout 它<br />
<blockquote class="tr_bq">
註:如需從origin拉下一個branch,需在本地創一個branch,checkout 後再拉 "origin/branchname"。eg. "git pull origin test"</blockquote>
<br />
<br />
<h3>
回溯:</h3>
git log // 取得過往的commit,其中以 hex code 為 id<br />
git checkout <hex code> // checkout 過往 commit<br />
git show // 顯示當前所在<br />
git checkout <branchname> // 回到 local 最新commit,eg. "git checkout master"<br />
<br />
<br />
<h3>
Tag:</h3>
git tag -l // 列出所有 tags<br />
git tag -a <tag name> <hex code> // 針對某一 commit 打 tag<br />
git push origin --tags // 上傳所有本機 tags 到 遠端<div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-86819917548836930492014-08-28T14:37:00.004+08:002014-08-28T14:37:45.234+08:00[SQL] Common Table Expression (CTE)CTE 簡單來說就是依據一定的查詢條件建立一個暫時的 table ,以便重複性的 Subquery 查詢。<br />
<br />
舉例來說,我需要從 pc, laptop, printer 三個 Table 取最貴的產品出來,想像的寫法可能是如此:<br />
<br />
<pre>SELECT model FROM (
SELECT * FROM pc
UNION
SELECT * FROM laptop
UNION
SELECT * FROM printer
)
WHERE price=(
SELECT MAX(price) FROM (
SELECT * FROM pc
UNION
SELECT * FROM laptop
UNION
SELECT * FROM printer
)
)
</pre>
<br />
我們會發現三個 table 的 UNION 被重複使用,非常麻煩。<br />
這時我們可以將這三個 table 的 UNION 暫存成 CTE,藉由以下的方式。<br />
<br />
<pre><span style="color: blue;">WITH</span> product <span style="color: blue;">AS</span> (
SELECT * FROM pc
UNION
SELECT * FROM laptop
UNION
SELECT * FROM printer
)
SELECT model FROM product
WHERE price=(
SELECT MAX(price) FROM product
)
</pre>
<br />
TADA~~~是不是簡單明瞭又方便勒?
<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-3169571258483080072014-08-09T02:42:00.001+08:002014-08-09T02:42:25.111+08:00ES6 新玩意兒 - Generatorㄜ....其實不太能算是新玩意了,畢竟小弟也好一陣子沒有繼續追JS的近況(廢)。<br />
實在是因為前陣子臉書上太多好友在提Kao和CO,當初用的express好像過時了一樣....<br />
<br />
<span style="font-size: large;">「不行!我還沒老啊!」</span><br />
<br />
身為一個技術潮人,臨時抱佛腳是必要的,就從ES6的新規範 - <b>Generator(迭代器)</b> 開始吧。<br />
<br />
<br />
<h3>
宣告方式</h3>
Generator 的宣告方式比較特別,有點像是 function ,基本上是長這樣:<br />
<br />
<pre>function * gen(){
console.log("start!");
yield "hello";
yield "I'm Kevin";
console.log("end!");
}</pre>
<br />
這個 gen 是一個ㄜ.....函式?總之,使用他後會返回一個 generator,像這樣:<br />
<br />
<pre>var g = gen(); // g 是一個 Generator
</pre>
<br />
<br />
這時,就可以拿它來做這樣的事:<br />
<br />
<pre>r = g.next(); // "start!"
console.log(r); // { value: "hello", done: false }
r = g.next();
console.log(r); // { value: "I'm Kevin", done: false }
r = g.next(); // "end!"
console.log(r); // { value: undefined, done: true }
</pre>
<br />
<br />
<h3>
Generator.next() 回傳什麼?Value & Done!</h3>
value的形式不拘,端看generator的yield後接著什麼,會被放到value中。<br />
至於 done 則是個單純的 boolean,告訴你這個 generator 玩完了沒。<br />
<br />
看到這邊,聰明的你應該可以得到一個結論,generator中的yield有點像是中斷點,當 next() 被執行時,generator內的程式碼開始被執行,直到下一個 yield 的那一行。直到 generator的最後一行,回傳 { done: true }。<br />
<br />
<br />
<h3>
Generator 也能接收資料</h3>
在迭代的過程中,我們也是可以將變數傳入next中的:<br />
<br />
<pre>function * gen(){
var got = yield "hello";
yield got;
}
var g = gen();
g.next("Good morning!"); // "Hello"
g.next(); // "Good morning!"
</pre>
<br />
TADA~~~很好玩吧?<br />
<br />
<br />
<h3>
Generator 的特性及用途</h3>
因為迭代器中斷函數時,是不會卡死其他程式碼的,這樣的特性非常適合拿來做同步處理。<br />
<br />
舉例來說....<br />
<br />
舉例來說....<br />
<br />
舉例來說....<br />
<br />
舉不出來,看看大大們怎麼說好了:<br />
<br />
<ul>
<li><a href="http://www.codedata.com.tw/javascript/es6-3-generator/" target="_blank">初探 Generator</a></li>
<li><a href="http://www.html-js.com/article/A-day-to-learn-JavaScript-to-replace-the-callback-function-with-ES6-Generator" target="_blank">用ES6 Generator替代回调函数</a></li>
</ul>
<br />
基本上主要是用作「非同步流程控管」及「解決回調地獄(callback hell)」用途使用。<br />
<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-42872677911090826052014-07-29T15:36:00.002+08:002014-07-29T15:38:11.360+08:00[JS] nextTick() 介紹與應用<br />
Node.js是單線程的,除了系統IO之外,在它的事件輪詢過程中,同一時間只會處理一個事件。你可以把事件輪詢想象成一個大的隊列,在每個時間點上,系統只會處理一個事件。即使你的電腦有多個CPU核心,你也無法同時並行的處理多個事件。但也就是這種特性使得node.js適合處理I/O型的應用,不適合那種CPU運算型的應用。在每個I/O型的應用中,你只需要給每一個輸入輸出定義一個回調函數即可,他們會自動加入到事件輪詢的處理隊列里。當I/O操作完成後,這個回調函數會被觸發。然後系統會繼續處理其他的請求。<br />
<br />
在這種處理模式下,process.nextTick()的意思就是定義出一個動作,並且讓這個動作在下一個事件輪詢的時間點上執行。我們來看一個例子。例子中有一個foo(),你想在下一個時間點上調用他,可以這麽做:<br />
<pre>function foo() {
console.error('foo');
}
process.nextTick(foo);
console.error('bar');
</pre>
<br />
執行結果將會是:<br />
<pre>bar
foo
</pre>
<br />
我們也可以使用setTimeout()函數來達到貌似同樣的執行效果:<br />
<pre>setTimeout(foo, 0);
console.log('bar');
</pre>
<br />
但在內部的處理機制上,process.nextTick()和setTimeout(fn, 0)是不同的,process.nextTick()不是一個單純的延時,他有更多的特性,這裡有兩者的<a href="https://gist.github.com/mmalecki/1257394" target="_blank">效能比較</a>。<br />
更精確的說,process.nextTick()定義的調用會創建一個新的子堆棧。在當前的棧里,你可以執行任意多的操作。但一旦調用netxTick,函數就必須返回到父堆棧。然後事件輪詢機制又重新等待處理新的事件,如果發現nextTick的調用,就會創建一個新的棧。<br />
<br />
<br />
<h3>
什麼時候會使用到 nextTick ?</h3>
因為JavaScript是單線程的Runtime,如果有需要長時間的運算,往往會卡死其他的程式,例如事件觸發的 function。<br />
更多應用情境可以參考<a href="http://www.oschina.net/translate/understanding-process-next-tick" target="_blank">原出處</a>。<br />
<br />
也可以參考Fred的這篇:<a href="http://fred-zone.blogspot.tw/2012/03/nodejs.html" target="_blank">探討 NODE.JS 的非同步機制</a><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com1tag:blogger.com,1999:blog-5705767416891474883.post-2908748806097279062014-02-19T16:22:00.000+08:002014-02-19T16:22:01.880+08:00在development模式下,assets 與 precompiled assets 衝突的解決方法因為自己的開發環境效能往往比production server 還好,有時候我們為了求快,會直接在local 將 assets precompile 過,上傳到 production。<br />
但繼續在 development 模式下開發時,就有個很機車的情況出現了,在 public/assets 中已經 compile 過的 assets 也被 require 進來,造成某些 lib 被 require 兩次而造成不正常的情況,當有新的變更時也會被舊的蓋過去。<br />
<br />
查了一下發現可以針對 development 模式對 asset 路徑加上prefix:<br />
<blockquote class="tr_bq">
config.assets.prefix = "/dev/assets"</blockquote>
<br />
這樣子 request 的路徑就會變成 /dev/assets/application.js ,避免被precompile的assets搞亂。<br />
<br />
<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-67200339284418918452014-02-12T15:26:00.001+08:002014-02-12T15:26:58.187+08:00修正 PG::UniqueViolation: ERROR: Duplicate Key Value Violates Unique Constraint 'Your_table_name_pkey' 問題<blockquote class="tr_bq">
PG::UniqueViolation: ERROR: Duplicate Key Value Violates Unique Constraint 'Your_table_name_pkey'</blockquote>
<div>
<br /></div>
今天在新產品上遇到了這個 error,查了一下發現是因為 postgres 因為不明原因而把 seq 搞亂了,以致於新增資料時使用到了既有資料的 id 。<br />
<div>
<br /></div>
<div>
了解問題所在後,循以下作法順利解決了問題:</div>
<div>
<ol>
<li> <code>rails db production</code></li>
<li> <code>SELECT setval('your_table_id_seq', (SELECT MAX(id) FROM your_table));</code></li>
</ol>
</div>
打完收工~<br><br><br><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-36015139311815379812014-01-08T00:50:00.001+08:002014-01-08T00:50:30.283+08:00Rails 的 i18n fallback 問題當在 config/application.rb 中指定了 config.i18n.fallbacks 語系順序後,別忘了要 comment 掉 produciton.rb 中的 <code>config.i18n.fallbacks = true</code> 。<br />
production 下的語系順序才會乖乖實現。<div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-14698030382630109922014-01-03T23:25:00.000+08:002014-01-06T10:35:00.870+08:00Unicorn + Nginx 配置及設定最近部屬公司的新產品 - <a href="http://flytutor.com/" target="_blank">flyTutor</a> 的時候,嘗試了不同的架構,從以往的 passenger-plugin on Nginx 換成了Unicorn 搭配 Nginx 的「反向代理」架構<br />
<br />
<h3>
What's "Reverse Proxy Model" ?</h3>
在提起 Unicorn 及 Nginx 的配置之前,我們得先了解一下「反向代理機制」,下面這張圖應該可以幫助你了解:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMbVGrT30tquxw9HLdobcLkBjP8uV42C2DK8owj5xZ49TzBOgIzll3i2ydPKiXjiEEbfQLOj0S4yhkdQbAG9d6gH_ETFRno9ypa4P3Fb7nFJVr_8IMtpevscnk1wiStK6fdMcoCfgUn6a2/s1600/deployment-proxy-diagram.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMbVGrT30tquxw9HLdobcLkBjP8uV42C2DK8owj5xZ49TzBOgIzll3i2ydPKiXjiEEbfQLOj0S4yhkdQbAG9d6gH_ETFRno9ypa4P3Fb7nFJVr_8IMtpevscnk1wiStK6fdMcoCfgUn6a2/s1600/deployment-proxy-diagram.jpg" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">(轉自: <a href="http://ihower.tw/rails3/deployment.html" target="_blank">ROR實戰聖經</a>)</td></tr>
</tbody></table>
<br />
<br />
在用戶端向 server 作請求的時候,不是直接與 app server 連結 (中間那三個),而是先連到 web server ,通常是 Apache 或 Nginx,再由 web server 指派 request 給 app server、或直接 serve static assets。<br />
所以在這樣的架構下你可以想像你的系統需要常駐著以下的服務:<br />
<ol>
<li>web server</li>
<li>數個 app server</li>
<li>DB server</li>
</ol>
<br />
這樣的架構是與常見的 Apache/Nginx + Passenger 架構有所不同的,需要作一點觀念上的調適。下面我們就來介紹一下如何做相關的配置。<br />
<br />
<br />
<h3>
Nginx 配置</h3>
以下是預設的 Nginx 設定檔 - nginx.conf:<br />
<pre>user deployer; # 定義操作 nginx 的使用者
worker_processes 1; # 定義 worker 的數量
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_vary off;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/rss+xml application/atom+xml text/javascript application/javascript application/json text/mathml;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\.";
server_names_hash_bucket_size 64;
types_hash_max_size 2048;
types_hash_bucket_size 64;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}</pre>
<br />
上面這段預設的設定檔有兩個地方需要注意:<br />
第一行的使用者身分必須為負責 deploy 的用戶,否則常常會出現 403 權限問題,因為未經設定的話 nginx 會沒有權限存取 deployer 的檔案,如 js, css。<br />
第二行的 worker 數量建議別設定超過 cpu 數目,多了也沒好處。<br />
<br />
再來就是重頭戲了,我們要開始加入 app server 的設定,這段設定需要加在 http 的括號內:<br />
<pre> upstream unicorn {
server 127.0.0.1:8080 fail_timeout=0;
}
server {
listen 80 default deferred;
server_name flytutor.com;
root /var/www/flytutor/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://unicorn;
}
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
</pre>
<br />
<h4>
upstream:</h4>
首先我們先來講解一下第一部分的 upstream。首先,upstream 後的「unicorn」並非一定的,端看你希望怎麼命名,但是要注意的是 proxy_pass 也需作對應的設定。再來,upstream 內的 server 可以不只一個,如果你有數個 app server 在不同的 host 的話,你也可以做如下的設定:<br />
<pre>upstream flytutor.com {
server 192.168.0.111:8080 weight=3;
server 192.168.0.222:8080 weight=2;
server 192.168.0.333:8080 weight=3;
}
</pre>
其中 weight 代表的是「被配發 request 的權重」,當 weight 越高的時候被分配到的機率越大,可以做 loading balance。<br />
<br />
而除了走 TCP/IP 外,如果是在 web server 和 app server 都在同一個主機的情況下,你也可以使用 socket 來做設定,基本上效能會比 TCP/IP 好一點點(因為少了 header):<br />
<pre> upstream unicorn {
server unix:/tmp/unicorn.sock fail_timeout=0;
}
</pre>
<br />
<h4>
server:</h4>
接下來我們要介紹一下 server 的設定,基本上這邊指的 server 就是指 app server,一台 nginx server 可以依 server 設定派發 request ,所以可以做 vhost 的應用,例如判斷 request 的不同網域 (設定檔中的 "server_name")、或是同網域但是不同 port (設定檔中的 "listen"),來派發到不同的服務。<br />
proxy_pass 很重要,許多網友都死在這個地方,切記要將他設置成 upstream 的命名,例如 "http://<upstream_name>"。<br />
你可以想像當一個 request 經過 location(path), server_name(domain), listen(port) 重重篩選後,你卻不指派 proxy_pass 的目的地給他,讓這個 request 就此隱沒在數據流中,成了「digital phantom」,你於心何忍?<br />
<br />
<br />
<h3>
Unicorn 配置</h3>
unicorn 的配置通常是放在 rails project 中的 config 資料夾,長得像這樣:<br />
<pre>app_root = "/var/www"
app_name = "flytutor"
<span style="color: red;">listen</span> "127.0.0.1:10101" #, :backlog => 2048 #這邊要跟nginx虛擬主機檔中upstream內定義的務必一樣
<span style="color: red;">worker_processes</span> 2 #看情況開
preload_app false
timeout 30
module Rails
class <<self
def root
File.expand_path(__FILE__).split('/')[0..-3].join('/')
end
end
end
_working_directory = File.join(app_root, app_name)
working_directory _working_directory
logs_path = "#{_working_directory}/log"
pid "#{_working_directory}/tmp/pids/unicorn.pid"
stderr_path "#{logs_path}/unicorn.stderr.log"
stdout_path "#{logs_path}/unicorn.stdout.log"
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true
before_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
old_pid = "#{Rails.root}/tmp/pids/unicorn.pid.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
puts "Send 'QUIT' signal to unicorn error!"
end
end
end
after_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end</pre>
<br />
這邊要注意的地方有兩個:
<br />
<br />
<ol>
<li>listen 的對象必須與 nginx.conf 中 upstream 設定的一樣,unicorn 與 nginx 就是靠這行設定連起來的。還有,如果是走 TCP/IP 的設定,盡量不要使用 1024 以下的 port 以免 deployer 沒有權限啟動 unicorn 導致失敗(你總不能老用 root 權限作 deploy 吧?)。</li>
<li>unicorn 是採用 master-slave 機制,啟動 unicorn 後叫出 process 列表你就會了解的。而這裡的 worker_processes 的數目顧名思義就是指定 worker 的數目。開多少個才好?基本上沒有一定的標準答案,還是要依你的使用情況及環境做測試後才知道,如果懶得想的話就直接設定為「CPU 數目 + 1」吧。</li>
</ol>
<br />
<br />
<h3>
操作 unicorn</h3>
許多網友在網路上搜尋到的啟動法是以 unicorn_rails 來啟動:<code>/usr/bin/unicorn_rails -c config/unicorn.rb -E $RAILS_ENV -D</code>。但現在 <a href="http://unicorn.bogomips.org/unicorn_rails_1.html" target="_blank">unicorn 官方已經不建議使用這種作法而是直接改用 <code>unicorn</code> 來啟動/重啟 unicorn</a>。<br />
<br />
<h4>
Hot restart with zero down time</h4>
許多人之所以選擇 unicorn 或許就是因為他的 hot restart 特性。如果對這有興趣的人可以參考<a href="http://stackoverflow.com/questions/18285215/unicorn-hot-restart-with-ruby-2-0-0-and-rails-3-2-14" target="_blank">這篇</a>。<br />
<br />
<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com2tag:blogger.com,1999:blog-5705767416891474883.post-23688157496049814422014-01-01T00:45:00.003+08:002014-01-01T00:45:57.703+08:00vagrant 初體驗與故障排除<h3>
1. 30 秒認識 vagrant:</h3>
Vagrant 是一個 ruby 寫的工具,它是一個 DSL 讓開發者可以輕易控制 VirtualBox 的 VM 。用它可以輕鬆管理和制作我們理想中的開發環境。<br />
<pre> $ gem install vagrant #安裝 vagrant
$ vagrant box add ubuntu http://cloud-images.ubuntu.com/vagrant/quantal/current/quantal-server-cloudimg-i386-vagrant-disk1.box #安裝新的 Vagrant Package。這裡的 ubuntu 是一個預先做好的空的 ubuntu 12.10 (intel-based)
$ vagrant init ubuntu
$ vagrant up
</pre>
box 檔可以在 <a href="http://www.vagrantbox.es/">http://www.vagrantbox.es/</a> 下載<br />
<br />
<br />
<h3>
2. 設定:</h3>
此時就可以使用 vangrant ssh 連到vm了,預設使用者/密碼為 vangrant/vangrant <br />
接著編輯本地資料夾中的 Vagrantfile,修改 <code>config.vm.network :hostonly, "33.33.33.33"</code> 將ip改成自己想要的ip,這裡以 "33.33.33.33" 為例。修改完後要執行 <code>vangrant reload</code> <br />
<br />
<br />
<h3>
3. 故障排除:</h3>
<br />
<h4>
無法以 SSH 連接 VM:</h4>
<blockquote class="tr_bq">
[default] Failed to connect to VM!<br />
Failed to connect to VM via SSH. Please verify the VM successfully booted<br />
by looking at the VirtualBox GUI.</blockquote>
當出現上面的錯誤訊息時,可以照 <a href="http://vagrant.wikia.com/wiki/Usage">http://vagrant.wikia.com/wiki/Usage</a> 上的步驟來排除,基本上就是將 Vagrantfile 中的 <code>config.vm.boot_mode = :gui</code> 設定打開。再重新 <code>vagrant up</code>,在產生的 GUI 中輸入 <code>sudo dhclient eth0</code>。<br />
<br />
<br />
<h4>
Guest additions not matchs:</h4>
<blockquote class="tr_bq">
[default] The guest additions on this VM do not match the install version of<br />
VirtualBox! This may cause things such as forwarded ports, shared<br />
folders, and more to not work properly. If any of those things fail on<br />
this machine, please update the guest additions and repackage the<br />
box.</blockquote>
<div>
解決方案:<a href="http://kvz.io/blog/2013/01/16/vagrant-tip-keep-virtualbox-guest-additions-in-sync/">http://kvz.io/blog/2013/01/16/vagrant-tip-keep-virtualbox-guest-additions-in-sync/</a><br />
<br /></div>
<br />
<br />
<h3>
Reference:</h3>
<a href="http://reality.hk/posts/2011/12/21/vagrant">http://reality.hk/posts/2011/12/21/vagrant</a><br />
<a href="http://gogojimmy.net/2013/05/26/vagrant-tutorial/">http://gogojimmy.net/2013/05/26/vagrant-tutorial/</a><br />
<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-77788047158284868282013-12-31T23:59:00.002+08:002014-01-01T21:40:39.670+08:00Rails query tips<h3>
Pluck - :</h3>
這個指令能讓搜尋結果的特定欄位獨立抽取出來放到 Array 裡,在很多情形下都很方便。<br />
Ex: <code>User.all.pluck :name # => ["Kevin", "Laura", "Yiya", "Diya"]</code><br />
<br />
<br />
<h3>
Subquery:</h3>
以第一個query的結果作為條件做搜尋,Ex:<br />
<code>Order.where( :product_id => Product.where("price<1000") )</code><br />
(Reference: http://ruby-china.org/topics/10771)<br />
<br />
<br />
<h3>
Update with condition:</h3>
Ex: <code>Model.where("state == 'decline'").update_all(:state => 'deny')</code><br />
<br />
<br />
<h3>
has_many relation with condition:</h3>
當兩個 model 彼此為一對多關係時,我們可以利用 condition 讓這個關係有所區分,我拿以下的情形為例:user 有很多訂單 (orders) ,有些是取消的、有些是處理中的、有些是已經結帳的。在這個情形下,用 user.orders 撈所有的訂單後再進行判斷顯然沒有效率、用 Order.where("{條件}") 的方法也就失去了 relation 的方便與直觀。這時我們可以做加上這幾個 relation:<br />
<pre>has_many :cancled_orders, :class_name=>"Order", :conditions=>proc{ "status = 'Cancled'" }
has_many :handling_orders, :class_name=>"Order", :conditions=>proc{ "status = 'Handling'" }
has_many :paid_orders, :class_name=>"Order", :conditions=>proc{ "status = 'Paid'" }
</pre>
<br />
這樣就可以透過如 <code>current_user.cancled_orders</code> 的方式取到「取消的訂單」了,相當直觀。<br />
<br />
<br />
<h3>
OR condition using Arel</h3>
Ex:<br />
<pre>t = Post.arel_table
results = Post.where(
t[:author].eq("Someone").
or(t[:title].matches("%something%"))
)
</pre>
<br />
<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-32735299771540096012013-12-30T12:07:00.001+08:002014-01-05T18:15:45.187+08:00動手寫一個 Rails plugin因為開發上方便,需要一個能快速切換登入身分的小 widget,正好趁這個機會搞懂怎麼開發一個 Rails plugin。成品在這:<a href="https://github.com/kevin-shu/user_switch">https://github.com/kevin-shu/user_switch</a><br />
以下就是步驟囉:<br />
<br />
<h3>
1. rails plugin new my_gem</h3>
首先執行 <code>rails plugin new <plugin_name></code>,會產生 plugin 資料夾,結構為:<br />
<blockquote class="tr_bq">
my_plugin<br />
├── Gemfile<br />
├── Gemfile.lock<br />
├── MIT-LICENSE<br />
├── README.rdoc<br />
├── Rakefile<br />
├── lib<br />
│ ├── <span style="color: red;">my_plugin</span><br />
│ │ └── <span style="color: red;">version.rb</span><br />
│ ├── <span style="color: red;">my_plugin.rb</span><br />
│ └── tasks<br />
│ └── my_plugin_tasks.rake<br />
├── <span style="color: red;">my_plugin.gemspec</span><br />
└── test<br />
│ <br />
...(本篇不提到,忽略)
</blockquote>
<div>
接下來就要介紹這些資料夾、檔案的用途</div>
<br />
<br />
<h3>
2. my_plugin.gemspec</h3>
這是一個 manifest 檔案,用來告訴 gem 該怎麼打包這個專案。<br />
<br />
<br />
<h3>
3. lib 資料夾</h3>
<h4>
my_plugin.rb:</h4>
這就是 plugin 的核心,當裝上 plugin 後,被執行的就是這個檔案。你當然可以將所有 code 都寫在裡面,但是這樣很亂。一個功能稍微複雜且完整的 plugin 一定會有系統的做模組化。所以我們往往不在裡面寫很多 code ,而是將一個個寫好的模組 require 近來。<br />
<br />
<h4>
my_plugin 資料夾:</h4>
剛剛說的模組化的 code 通常會被分門別類放在這裡。<br />
<br />
<h4>
my_plugin/version.rb:</h4>
在初始化後,my_plugin 資料夾一開始只有這個檔案,用來記錄版本號。你如果有看一下 gemspec 的內容的話,會發現這個檔案會被 gemspec require 到。<br />
<br />
<h4>
Engine</h4>
如果你的 plugin 需要一些自定的 controller、view、assets,首先要加入這段程式碼:<br />
<pre>module ZurbFoundation
class Engine < Rails::Engine
end
end</pre>
你可以將他獨立成一個檔案由 <code>my_plugin.rb</code> 載入,或是直接寫到 <code>my_plugin.rb</code> 裡。有了這段程式碼,Rails就會自動將 app 及 config 兩個資料夾下的所有檔案載入。<br />
<blockquote class="tr_bq">
請注意,載入 engine 的 code 必須放在 my_plugin.rb 的最後,才能正常運作</blockquote>
<br />
<br />
<h3>
4. app 資料夾</h3>
當你希望在安裝這個套件的專案中使用客製的 controller、assets 等檔案,就要在根目錄下建立一個 app 資料夾。結構基本上跟你熟悉的 rails 的 app 資料夾是一樣的。要注意的是,裡面的 controller 或 model 必須在 專案的 namespace 下,例如:<br />
<pre># CURRENT FILE :: app/controllers/my_plugin/my_controller.rb
<span style="color: #990000;">module MyPlugin</span>
class MyController < ::ApplicationController
def index
...
end
end
<span style="color: #990000;">end</span>
</pre>
<br />
<br />
<h3>
5. config</h3>
這個資料夾跟app資料夾一樣需要手動建立,最常見的用途是設定 routing,例如:<br />
<pre># CURRENT FILE :: config/routes.rb
Rails.application.routes.draw do
get "team" => "team_page/team#index" , :as => :team_page
end
</pre>
<br />
<br />
<h3>
6. generators 資料夾</h3>
這個資料夾也是需要時才要自行建立。裡面放了一些設定檔等的 template 以及 install method,讓這個 gem 提供 install 功能,執行後會複製一份設定檔到專案中。這邊不會對 generators 多做介紹。<br />
<br />
<br />
<h3>
7. pack & push</h3>
當你的 plugin 完成後,就可以用以下指令將他打包起來,gem 會按照 gemspec 的設定做打包。<br />
<blockquote class="tr_bq">
gem build /project_path/user_switch.gemspec</blockquote>
打包後的 gem 可以 push 到 rubygems.org:<br />
<blockquote class="tr_bq">
gem push project_name-0.0.1.gem</blockquote>
<br />
<br />
<h3>
8. 在 Rails 專案中掛上剛寫好的plugin push</h3>
我們有可以在 Gemfile 中依不同來源來做來源的設定,其中當來源是來自 local 或 git 時,是不用打包就可以直接掛上的,開發的時候來源通常是設定在 local。<br />
<h4>
(1) local: </h4>
<pre>gem "my_plugin", :path=>"/path/to/your/plugin"</pre>
<br />
<h4>
(2) git:</h4>
<pre>gem "my_plugin", :git=>"https://path/to/your/repo"</pre>
<br />
<h4>
(3) rubygem.org:</h4>
<pre>gem "my_plugin"</pre>
<br />
<br />
<h3>
Reference:</h3>
http://zurb.com/article/814/yetify-your-rails-new-foundation-gem-and-<br />
http://coding.smashingmagazine.com/2011/06/23/a-guide-to-starting-your-own-rails-engine-gem/<br />
http://guides.rubyonrails.org/plugins.html<div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-61473160428457164712013-12-24T20:01:00.001+08:002013-12-24T20:01:54.727+08:00Rails 的 Assets ConvensionRails 開發者應該都知道 assets 的路徑原則<br />
<br />
<ol>
<li>app/assets/ 放自己的 assets</li>
<li>vendor/assetes/ 放第三方assets</li>
</ol>
<br />
<br />
但是在 app/assets 底下無法 require_tree vendor底下的資料夾,只能 require 單一檔案。要達到同樣的效果只要 require vendor的檔案,這個檔案再 require_tree 即可。<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-17417427096717670522013-12-17T23:58:00.002+08:002013-12-17T23:58:38.519+08:00warning: toplevel constant Model referenced by NS::Model<br />
今天遇到了這個問題,在網上搜一下找到一個滿詳盡的解釋,茅塞頓開:<br />
<blockquote class="tr_bq">
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">
Your <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 1px 5px; vertical-align: baseline;">User::File</code> class is not loaded. You have to require it (e.g. in <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 1px 5px; vertical-align: baseline;">user.rb</code>).</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">
The following happens when ruby/rails sees <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 1px 5px; vertical-align: baseline;">User::Info</code> and evaluates it (simplified; only <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 1px 5px; vertical-align: baseline;">User</code> is defined yet).</div>
<ul style="background-color: white; border: 0px; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; list-style-image: initial; list-style-position: initial; margin: 0px 0px 1em 30px; padding: 0px; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">check if <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">User::Info</code> is defined - it is not (yet)</li>
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">check if <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">Info</code> is defined - it is not (yet)</li>
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;"><code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">uninitialized constant</code> -> do rails magic to find the <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">user/info.rb</code> file and require it</li>
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">return <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">User::Info</code></li>
</ul>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">
Now lets do it again for <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 1px 5px; vertical-align: baseline;">User::File</code></div>
<ul style="background-color: white; border: 0px; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; list-style-image: initial; list-style-position: initial; margin: 0px 0px 1em 30px; padding: 0px; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">check if <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">User::File</code> is defined - it is not (yet)</li>
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">check if <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">File</code> is defined - it is (because ruby has a built in <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">File</code> class)!</li>
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">produce a warning, because we've been asked for <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">User::File</code> but got <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">::File</code></li>
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">return <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 0px; vertical-align: baseline;">::File</code></li>
</ul>
</blockquote>
<br />
裡面提到了要手動 Require NameSpace 下的 Model,但是如果 NS 下的 model 本身有繼承到 NS 外的 Model,要確保在父類別宣告後建立才行。所以最好是在父類別檔案的結尾處 require。<div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-84441215402938339822013-12-12T01:30:00.000+08:002013-12-24T20:23:56.188+08:00以 STI (Single Table Inheritance) 及 NameSpace 提高專案維護及可讀性正在開發的產品中,有個「個人資料維護功能」需要記錄使用者的學歷。我採用的架構是:<br />
<ul>
<li>user has_many educations</li>
<li>education belongs_to school</li>
</ul>
<br />
而且 educations 和 schools 資料表中各有 type 和 stage 欄位記錄這個 學歷/學校 是屬於哪個階段 (ex. 國中、高中、大學)。(題外話,type 在 Rails 中是個欄位的保留名稱,專門給 STI 使用)<br />
<br />
在這樣的情況下,當我使用 <code>user.educations</code> 取得使用者學歷後,還需要再進行 <code>Array.detect</code> 來找對應的階段來顯示「國中讀哪裡」、「高中讀哪裡」,這樣的邏輯實作出來相當冗餘也不好看。<br />
<br />
<br />
<h3>
用 STI 來讓多型別的 relation 更直觀</h3>
<br />
於是我便將架構做一點改變,新增幾個 education 的 sub-class,放在 "education" 的 NameSpace 下避免與既有的 model 撞名。並將 stage 改為 type,以建立 STI 的從屬關係,例如:<br />
<pre>class Education::HighSchool < Education
...
end
</pre>
<br />
這樣一來,我們只要再建立以下的 relation,就可以使用 user.high_school 和 user.junior_high_school 直接拿到對應學歷,相當直覺:<br />
<ul>
<li>has_one :junior_high_school, :class_name=>"Education::JuniorHighSchool"</li>
<li>has_one :high_school, :class_name=>"Education::HighSchool"</li>
</ul>
<br />
<br />
<h3>
STI name hack</h3>
<br />
但在這樣的情況下,因為 Rails 的 convention,他會預設抓取 type 為 "Education::JuniorHighSchool" 或 "Education::HighSchool" 的 education。但是這樣很醜,並不直覺。我希望在type中顯示 "JuniorHighSchool" 或 "HighSchool" 就好。這時我們可以在他們的父類別,也就是 education.rb 加入以下程式碼來 hack :<br />
<pre>class Education < ActiveRecord::Base
...
<span style="color: #cc0000;"> class << self
def find_sti_class(type_name)
("Education::"+type_name).constantize()
end
def sti_name
name.demodulize
end
end</span>
end
</pre>
<br />
<b>find_sti_class</b> 的用途是:在 table 中找到一個 entry 時,決定用什麼 model 來表達他,而傳入的 type_name 當然就是 type 欄位中的資料了。當我們如範例程式碼重寫 find_sti_class 後,如果傳入的 type_name 為 「HighSchool」,find_sti_class 會返回 <code>Education::HighSchool</code> 這個Class。<br />
<br />
<b>sti_name</b> 則是在 new 一個繼承 STI 的物件時,將 return 的值塞進 type 欄位。經過範例程式法的改寫後,新增一筆 <code>Education::HighSchool</code>資料時,Rails 會在type欄位中存入經過 demodulize 的字串「HighSchool」,而不是 <code>Education::HighSchool</code>。<br />
<br />
這樣一來 Rails 就會乖乖找type為 "HighSchool" 的 <code>Education::HighSchool</code> model了。<br />
<br />
<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-63593877861717137952013-12-11T19:43:00.002+08:002013-12-11T19:45:06.060+08:00Rails 的 db:migration 及 db:schema:load相信 rails 開發者對 rake db:migrate 這個指令相當熟悉,但是可能比較少機會用到 rake db:schema:load,他是拿來幹嘛的?<br />
<br />
<h3>
db:migrate 的用途</h3>
<br />
在多個環境或多人開發的時候,我們會頻繁的使用 <code>db:migrate</code> ,為得是將各個環境的資料庫結構給同步起來,而不用使用同一個資料庫來開發。使用同一個資料庫除了會弄髒彼此的還境外,也會造成每改一次資料庫,就要確認其他開發者的程式碼是 workable 的,也就是「<span style="color: #990000;">schema和程式碼不同步</span>」的情形。<br />
<br />
在這樣的情形下,將 migration 寫成腳本並加上 time stamp ,在<span style="color: #990000;">各自環境的資料庫各自進行 migration </span>就成了一個最合理的 solution 了。而因為 migration 腳本就是整個專案程式碼的一部分,也就解決了schema 及程式碼的同步問題。每個開發者可以依照自己的進度 commit、pull、merge,再執行 <code>rake db:migrate</code> ,資料庫就同步了。<br />
<br />
但是在開發過程,尤其是初期的 scratch 階段,常常會有一堆冗餘的動作,例如:<br />
<ol>
<li>創建 users 資料表</li>
<li>加兩個欄位到 users 資料表</li>
<li>刪除 users 的其中一個欄位</li>
<li>再加一個欄位到 users 資料表</li>
</ol>
<br />
這時就會在系統中留下四個針對 users 資料表的 migration 腳本。這時如果有一個新加入的開發者,將程式碼拉到自己建立的新環境,使用 <code>rake db:migrate</code> 這個指令後, rake 就會乖乖的幫你分四個步驟做完,其實很沒必要也很笨。<br />
<br />
<br />
<h3>
db:schema:load 幫你直接從 schema.rb 初始化資料庫結構</h3>
<br />
其實在你進行migration的時候,rake 也產出了一份資料庫的架構檔案,叫做「schema.rb」,這個檔案記錄了這個專案的資料庫目前的架構。檔案中也會有一個 timestamp 記錄這是什麼時候的結構,用以區分先後順序。<br />
<br />
而當有新的環境要被建立,或是重置資料庫的時候,我們可以利用 <code>rake db:shema:load</code> 這個指令讓資料庫「一步到位」,而不用一步步的照 migration 腳本來設置資料庫。<br />
<br />
<br />
<br /><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-92218423102805239692013-12-11T18:56:00.004+08:002013-12-11T18:56:53.638+08:0060fps scrolling using "pointer-events: none"<br />
<br />
Reference: <a href="http://www.thecssninja.com/javascript/pointer-events-60fps">http://www.thecssninja.com/javascript/pointer-events-60fps</a><div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-75823334463742917962013-12-11T11:49:00.000+08:002013-12-11T11:49:13.483+08:00Eager & Lazy LoadingEager Loading 就是事先將可能會用到的 resource 給準備好。<br />
Lazy Loading 則相反,等到用到時才去fetch。<br />
<br />
這兩個技術名詞聽起來沒什麼學問,但他代表了兩種不同的策略。何時該用哪一種是需要用經驗來判斷的,沒有孰好孰壞的問題。<div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-60482837867206003342013-12-06T23:22:00.003+08:002013-12-19T23:06:00.490+08:00用ngrok將公開網址指向你的localhost 在本機端開發網站的過程中,我們會遇到幾個情況:<br />
要給夥伴看目前的進度<br />
要接第三方的Oauth驗證<br />
但如果是在家用adsl上網,會發生沒有實體ip可以接的窘境,這時我們可以使用 <a href="https://ngrok.com/" target="_blank">ngrok</a> 的服務來產生一個公開的internet網址。<br />
<br />
<h3>
註冊Ngrok</h3>
當你沒有註冊會員時,只能隨機產生subdomain,例如:<br />
<blockquote class="tr_bq">
ngrok 80 #http://580ef28f.ngrok.com</blockquote>
<br />
在你註冊過Ngrok的免費會員後,可以在後台取得authtoken,進而指定自己想要的subdomain:<br />
<blockquote class="tr_bq">
ngrok -subdomain <your subdomain> -authtoken <your authtoken> 3000</blockquote>
<div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0tag:blogger.com,1999:blog-5705767416891474883.post-41267637830632285102013-11-21T18:37:00.003+08:002013-11-21T18:37:30.853+08:00[轉錄] 專訪引號科技團隊,十二年國教競爭力分析平台「國教通」上線 (轉自 TechOrange 橘子聚光燈)<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; text-align: center; vertical-align: baseline;">
<a href="http://techorange.com/2013/10/28/quot-tw-and-milestones/milestone/" rel="attachment wp-att-92130" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><img alt="" class="size-large wp-image-92130 aligncenter" height="287" src="http://techorange.com/wp-content/uploads/2013/10/milestone-550x287.png" style="background-color: transparent; border: 0px; margin: 25px 0px; max-width: 620px; outline: 0px; padding: 0px; vertical-align: baseline;" title="milestone" width="550" /></a></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
「十二年國教」已經在今年六月由立法院三讀通過、拍板定案,2014 年正式上路。也就是說,現在就讀國三的學生,明年升高中時必須透過免試入學或特色招生的方式入學。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
我們都知道,政府是在期望學生能夠全能發展的立意下推動十二年國教,然而,多如牛毛的規則始終讓其難以親近。入學方式分為免試入學與特色招生,但免試入學滿額後還要依超額比序、不同學區又各自有不同的比序,弄得家長、學生一頭霧霧水,許多家長從「搞不懂」十二年國教變成「不想搞懂」十二年國教,甚至直接把孩子丟到私立學校,一路直升,免除相關問題。自然而然大家也就感受不到政府的美意。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
但大家有沒有想過,或許我們根本不必弄懂十二年國教多如牛毛的規則?</div>
<ul style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; list-style: circle; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; font-weight: bold; list-style: url(http://techorange.com/wp-content/uploads/2011/12/tiny_orange.jpg); margin: 0px 0px 0px 15px; outline: 0px; padding: 0px; vertical-align: baseline;"><span style="background-color: transparent; border: 0px; color: maroon; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">十二年國教競爭力分析平台:《</strong><strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">MilestoneS </strong><strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">國教通》</strong></span></li>
</ul>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
「<a href="http://milestones.cc/" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;" target="_blank">MilestoneS 國教通</a>」(以下簡稱國教通)是一個幫助學生、家長、教師甚至補教業者更加了解學生學習狀況,並可以依照學生學習進度,規畫未來學習方向的平台。只要學生把想申請的學校、現有的學習進度填進系統,就能以清楚、明瞭的量化資料,了解到距離自己第一志願的不足之處,並能針對應加強之處給予建議,同時也可以一掃家長、學生對於十二年國教的一頭恐懼。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
藉由國教通發表的機緣下,我們認識並訪問了其開發團隊<a href="http://quot.tw/" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;" target="_blank">引號科技</a>的三個大男生:技術經理束凱文、軟體工程師劉軒銘、UX 經理劉大智。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
十二年國教的規則有多複雜,我切身體驗過。在我為了瞭解國教通進而搜尋十二年國教相關資料時,也不免在幾個較為複雜的問題卡關,像是超額比序中的「就近入學」、「共同學區」等,而我相信,這些問題也同樣會困擾家長。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
引號科技看見家長、學生的問題,推出台灣第一個整合全台灣 15 個不同學區超額比序資料與規則的平台。操作方式力求簡單、整潔、好上手,藉由第一次登入時的快速導覽,讓第一次使用的學生、家長可以很快地了解國教通的使用方法。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; text-align: center; vertical-align: baseline;">
<a href="http://techorange.com/2013/10/28/quot-tw-and-milestones/1-31/" rel="attachment wp-att-89551" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><img alt="" class="size-large wp-image-89551 aligncenter" height="337" src="http://techorange.com/wp-content/uploads/2013/09/13-550x337.png" style="background-color: transparent; border: 0px; margin: 25px 0px; max-width: 620px; outline: 0px; padding: 0px; vertical-align: baseline;" title="1" width="550" /></a></div>
<ul style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; list-style: circle; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; font-weight: bold; list-style: url(http://techorange.com/wp-content/uploads/2011/12/tiny_orange.jpg); margin: 0px 0px 0px 15px; outline: 0px; padding: 0px; vertical-align: baseline;"><span style="background-color: transparent; border: 0px; color: maroon; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">國教通的優勢在哪裡?</span></li>
</ul>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
<span style="background-color: transparent; border: 0px; color: magenta; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">1. 量化、圖片化(圖表化)完成程度,家長學生</strong></span><strong style="background-color: transparent; border: 0px; color: magenta; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">有目標</strong></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; text-align: center; vertical-align: baseline;">
<a href="http://techorange.com/2013/10/28/quot-tw-and-milestones/e/" rel="attachment wp-att-90317" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><img alt="" class="size-full wp-image-90317 aligncenter" height="547" src="http://techorange.com/wp-content/uploads/2013/09/E.png" style="background-color: transparent; border: 0px; margin: 25px 0px; max-width: 620px; outline: 0px; padding: 0px; vertical-align: baseline;" title="E" width="513" /></a></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
只需按表輸入學生的相關資料如幹部經歷、檢定證照、競賽表現等,再填入志願學區,國教通就會依照這些資料自動整理成易懂的量化模式,學生只需像完成遊戲關卡一般將表格慢慢填滿。當然填入的資料越齊全,在未來落點分析預測越準確。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
<span style="background-color: transparent; border: 0px; color: magenta; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">2. <strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">自主學習有方向,工欲善其事,必先利其器。</strong></strong></span></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; text-align: center; vertical-align: baseline;">
<a href="http://techorange.com/2013/10/28/quot-tw-and-milestones/d/" rel="attachment wp-att-90316" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><img alt="" class="alignnone size-large wp-image-90316" height="125" src="http://techorange.com/wp-content/uploads/2013/09/D-550x125.png" style="background-color: transparent; border: 0px; margin: 25px 0px; max-width: 620px; outline: 0px; padding: 0px; vertical-align: baseline;" title="D" width="550" /></a></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
除了簡單易懂的模式與量化的圖表之外,學生還能透過國教通分析自己在十二年國教制度下的競爭力,並透過其中的客製化得分建議,清楚理解自己的不足之處,可以針對弱點處加強。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
我們甚至可以預見有學生可以透過這個平台,在與家長共同規畫下,擁有清楚、明確的長短期努力方向,不必補習就可以進入自己的第一志願。這也許比一味的補習、填鴨更符合教育的本意。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; text-align: center; vertical-align: baseline;">
<a href="http://techorange.com/2013/10/28/quot-tw-and-milestones/3-24/" rel="attachment wp-att-89558" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><img alt="" class="size-large wp-image-89558 aligncenter" height="153" src="http://techorange.com/wp-content/uploads/2013/09/3-550x153.png" style="background-color: transparent; border: 0px; margin: 25px 0px; max-width: 620px; outline: 0px; padding: 0px; vertical-align: baseline;" title="3" width="550" /></a></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
<span style="background-color: transparent; border: 0px; color: magenta; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">3. 在未來國教通還可以 ……</strong></span></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
隨著使用國教通的使用者越來越多,國教通可以帶來更多精準的預測,例透過越來越多人的區域、志願序甚至模擬考成績排名來做落點分析,使用的人越多,落點分析越精準。再加上引號科技也表示,未來政府若有相關政策修改,國教通也會馬上改版,調整到適合該年度政策的模式,家長與學生可以不用活在驚慌之中。</div>
<ul style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; list-style: circle; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; font-weight: bold; list-style: url(http://techorange.com/wp-content/uploads/2011/12/tiny_orange.jpg); margin: 0px 0px 0px 15px; outline: 0px; padding: 0px; vertical-align: baseline;"><span style="background-color: transparent; border: 0px; color: maroon; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">規則過於複雜,家長學生卻步</span></li>
</ul>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; text-align: center; vertical-align: baseline;">
<a href="http://techorange.com/2013/10/28/quot-tw-and-milestones/all-2/" rel="attachment wp-att-91841" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><img alt="" class="size-large wp-image-91841 aligncenter" height="243" src="http://techorange.com/wp-content/uploads/2013/09/all-550x243.jpg" style="background-color: transparent; border: 0px; margin: 25px 0px; max-width: 620px; outline: 0px; padding: 0px; vertical-align: baseline;" title="all" width="550" /></a></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
訪問當天我們直接以「為什麼要做國教通?」做為開頭,這個問題由在訪問中話不多的軟體工程師劉軒銘(左)回答道:「我們一直有在關注教育方面的問題,同時也認為政府推動十二年國教是一件好事、美意,但,學生、家長卻因為相關計算的複雜性而感到卻步,這不是很可惜嗎?」</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
從「開始想要解決十二年國教問題」到「第一版國教通上線」,技術經理束凱文(中)向我們表示大約花了一個多月的時間,花費時間不算長,並不是他們特別「神」,而是他們之前就有過開發專案的經驗,但他們也坦承,在開發期間根本沒日沒夜,畢竟光是搞懂十二年國教的規則就花了不少時間,而他們還要把這些規則演繹成一套演算法,更要依據 15 個學區不同的計算方法來調整演算法。不過他們還是做出來了。</div>
<ul style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; list-style: circle; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; font-weight: bold; list-style: url(http://techorange.com/wp-content/uploads/2011/12/tiny_orange.jpg); margin: 0px 0px 0px 15px; outline: 0px; padding: 0px; vertical-align: baseline;"><span style="background-color: transparent; border: 0px; color: maroon; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">要如何推廣國教通?</span></li>
</ul>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
束凱文告訴我們,國教通最大的競爭對手,便是在地的相關服務。儘管國教通是第一個整合全台 15 個不同學區的系統,但部分學區已經有類似國教通的服務,外來的國教通想要打進各地早已自成一格的校務系統、補習班、學生網絡,不免有些困難。全面上線的同時,也與高雄、新竹地區校務系統商合作,整合兩地自有的校務系統直登入,為踏入各地學區的第一步。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
國教通目前也積極地與提供各校模擬考的廠商洽談合作,將國教通當作模擬考的加值服務,讓考試分數直接匯入國教通系統、建檔在學生資料裡。這麼一來,除了可以蒐集到更多學生的模擬考成績,這些廠商也自然而然的成為推展國教通的業務。</div>
<ul style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; list-style: circle; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; font-weight: bold; list-style: url(http://techorange.com/wp-content/uploads/2011/12/tiny_orange.jpg); margin: 0px 0px 0px 15px; outline: 0px; padding: 0px; vertical-align: baseline;"><span style="background-color: transparent; border: 0px; color: maroon; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">在我眼中,國教通還有什麼?</span></li>
</ul>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
<span style="background-color: transparent; border: 0px; color: magenta; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">1. 資料的商機</strong></span></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
我第一次了解到國教通時,除了覺得量化、圖片化複雜的十二年國規則是個非常好的主意之外,更覺得背後的商機不容小覷。如果今日國教通已經擁有部分學生的模擬考資料,是否可以針對某些科目較差的學生投放該科目的廣告?我相信使用國教通的使用者除了學生之外,家長也占了不少比例,如果有辦法進行精準行銷,非常有可能促使擔憂的家長打開錢包把小孩送去補習,這代表,補習班業者會願意打開錢包投放廣告。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
除了這點之外,隨著使用者越來越多,國教通將掌握更多有價值的資料,這些資料都像是一座一座的金礦,等待挖掘。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
當我們問起是否會以使用者的資料來投放不一樣的廣告時,束凱文說這還在未來的計劃中,目前首要的目標是增加使用國教通的人數。不過可以確認的是,他們絕對不會販賣、洩漏使用者的個資,而其他的廣告商機、資料商機,目前仍在規劃中。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
<span style="background-color: transparent; border: 0px; color: magenta; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">2. 更瘋狂的填鴨式教育?</strong></span></div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
除了商機之外,使用國教通這類產品,會不會造成更瘋狂的填鴨教育?過往由於家長、學生沒有明確的目標,就是一味的補習補習補習,把每一個科目的分數衝高、追求第一志願,現在有了國教通,家長是否會按表操課,逼迫學生除了追求高分之外,還要當幹部、做志工服務以符合進入明星高中的門檻?</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
劉軒銘說,這絕對不是國教通的本意,也不會是教育的本意。十二年國教就是為了讓學生可以全能發展,不過擠入明星高中就是台灣目前的現況,只能期望學生們擠入明星高中之後可以好好省思一下自己未來的方向,而不是不斷地堆砌學歷。</div>
<ul style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; list-style: circle; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; font-weight: bold; list-style: url(http://techorange.com/wp-content/uploads/2011/12/tiny_orange.jpg); margin: 0px 0px 0px 15px; outline: 0px; padding: 0px; vertical-align: baseline;"><span style="background-color: transparent; border: 0px; color: maroon; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">創業、工作,年經人如何抉擇?</span></li>
</ul>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
看到這三個有理想、腦子動得快的年輕人,也不禁讓我們想了解國教通背後的開發公司,引號科技。在引號科技中負責網頁 UX 與設計的劉大智(上圖右)不厭其煩地向我們解釋了許多關於引號科技的小細節,包含引號科技目前的工作範疇:他們以由專案的 UX、流程規劃、App 開發、Data Mining 起家,曾與裕隆集團、華南銀行合作過,目前也有幾個的專案正在進行中,完全由內部主導開發的國教通便是其中之一。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
引號科技目前成員只有五人,但他們不同的專案由不同的人主導,之後再向外尋找業務人選或是合作對象的方式,讓小小團隊也可以運行許多專案。例如此次的國教通專案由束凱文主導,除了來訪的軒銘與大智之外,在南部也有他們成大的學弟加入團隊運作。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
引號科技的團隊人員都非常的年輕就走上創業之路,當我以「身為一個過來人,是否鼓勵年輕人自己創業」當作訪問的結尾時,束凱文語重心長地說:「最好在創業之前先工作過,才能了解到很多事情是怎麼運作的,不要抱著滿懷熱血最後卻得到一場空」。當然,這僅是他的答案,不過我相信有過不少經歷的他會這樣講,必然有一些道理。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
最後,正如引號科技對自己的期許「希望可以回饋社會、為社會創造更大的價值與福祉」,這個理念我們在國教通身上看到了,也期望他們可以貫徹自己的理念,並懷抱著夢想不斷前進。</div>
<div style="background-color: white; border: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 28.5px; margin-bottom: 1.5em; outline: 0px; padding: 0px; vertical-align: baseline;">
(圖片來源:人物圖片由圖片本人提供、<strong style="background-color: transparent; border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;"><a href="http://milestones.cc/" style="background-color: transparent; border: 0px; color: #f16522; cursor: pointer; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;" target="_blank">Milestones 國教通</a></strong>)</div>
<div class="blogger-post-footer"><a name="xn_share" type="button_count_top" href="#">分享到人人</a><script src="http://static.connect.renren.com/js/share.js" type="text/javascript"></script></div>貓桑http://www.blogger.com/profile/01978864455251846796noreply@blogger.com0