<?xml version="1.0" encoding="utf-8" standalone="no"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0"><channel><title>黃金俠</title><managingEditor>marsz330@gmail.com (MarsZ)</managingEditor><pubDate>Tue, 11 Jun 2013 10:10:46 +0800</pubDate><generator>Octopress http://octopress.org/</generator><language>en-us</language><itunes:explicit>no</itunes:explicit><itunes:owner><itunes:email>marsz330@gmail.com</itunes:email></itunes:owner><item><title>透過 sidekiq 實作背景工作 (background job)</title><pubDate>Sat, 8 Jun 2013 15:08:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-06-08/sidekiq</guid><description>&lt;p&gt;&lt;code&gt;sidekiq&lt;/code&gt; 是一套可以用來實作 background job 的 gem&lt;br/&gt;
舉凡長時間的執行如 email, 點數計算等等非即時性的工作, 都可以採用非同步執行&lt;br/&gt;
以加速前端服務的反應速度或減低主機負荷&lt;br/&gt;
和 &lt;code&gt;resque&lt;/code&gt; 一樣，&lt;code&gt;sidekiq&lt;/code&gt; 是以 redis 做為 &lt;code&gt;Message Queue&lt;/code&gt; 來運作&amp;#8230;&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h3&gt;安裝&lt;/h3&gt;

&lt;p&gt;本教學所使用的版本是 2.12.1&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Gemfile&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;sidekiq&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;~&amp;gt; 2.12.1&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;設定 redis&lt;br/&gt;
關於 redis 安裝可參考 &lt;a href="http://pm.5fpro.com/projects/public-wiki/wiki/Redis" target="_blank"&gt;http://pm.5fpro.com/projects/public-wiki/wiki/Redis&lt;/a&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure_server&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:url&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;redis://127.0.0.1:6379/0&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure_client&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:url&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;redis://127.0.0.1:6379/0&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;使用 (定義 worker)&lt;/h3&gt;

&lt;p&gt;定義 worker&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;foo_worker.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FooWorker&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;sidekiq_options&lt;/span&gt; &lt;span class="ss"&gt;:queue&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:barbar_queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:retry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:backtrace&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;啟動 worker (-c 代表  concurrency worker 數)&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;sidekiq&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;把工作丟到 queue 裡&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;FooWorker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;perform_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;haha&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;這時若有啟動 worker 就會從 redis 把工作抓下來執行&lt;/p&gt;

&lt;h3&gt;使用 (delay methods)&lt;/h3&gt;

&lt;p&gt;直接丟到 queue 裡&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Bar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;haha&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;也可以以 instance 丟&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;increase_credit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;延遲至某短時間後再讓 worker 執行&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delay_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;increase_credit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;延遲至某個時間點再給 worker 執行&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delay_until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;increase_credit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;設定 Web console&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Gemfile&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;slim&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sinatra&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;gt;= 1.3.0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/routes.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sidekiq/web&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Web&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/sidekiq&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;web console 想要綁 devise 登入 (假設 scoep 為 member 且 &lt;code&gt;.is_admin&lt;/code&gt; 必須為 true )&lt;br/&gt;
(更多可參考 &lt;a href="https://github.com/mperham/sidekiq/wiki/Monitoring" target="_blank"&gt;https://github.com/mperham/sidekiq/wiki/Monitoring&lt;/a&gt;)&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/routes.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;sidekiq_constraints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;warden&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;authenticate!&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;:scope&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:member&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;warden&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:member&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_admin&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;constraints&lt;/span&gt; &lt;span class="n"&gt;sidekiq_constraints&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Web&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/sidekiq&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;佈署&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/deploy.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:sidekiq_cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bundle exec sidekiq&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:sidekiqctl_cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bundle exec sidekiqctl&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sidekiq/capistrano&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/sidekiq.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='line'&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;:verbose&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;:concurrency&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;staging&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:concurrency&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;production&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:concurrency&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:queues&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="p-Indicator"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="p-Indicator"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="p-Indicator"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="p-Indicator"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;mailer&lt;/span&gt;&lt;span class="p-Indicator"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;9&lt;/span&gt;&lt;span class="p-Indicator"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;venus&lt;/h3&gt;

&lt;p&gt;上述設定也可透過 gem &lt;code&gt;venus&lt;/code&gt; 完成&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;rails&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="n"&gt;venus&lt;/span&gt;&lt;span class="ss"&gt;:sidekiq&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;參考教學&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://railscasts.com/episodes/366-sidekiq" target="_blank"&gt;RailsCast&lt;/a&gt;&lt;br/&gt;
&lt;a href="https://github.com/mperham/sidekiq/wiki" target="_blank"&gt;Official Document&lt;/a&gt;&lt;/p&gt;
</description></item><item><title>讓 S3 允許 cross-domain 存取</title><pubDate>Thu, 6 Jun 2013 01:48:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-06-06/aws-s3-allow-cross-origin-access</guid><description>&lt;p&gt;檔案放上 &lt;code&gt;S3&lt;/code&gt; 後，可能會需要透過 &lt;code&gt;cross-domain&lt;/code&gt; 存取 (例如 web font)&lt;br/&gt;
這時可以透過 &lt;code&gt;S3&lt;/code&gt; bucket 的 &lt;code&gt;CORS&lt;/code&gt; 設定達成&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;&lt;img src="http://i.imgur.com/7vjeF3g.png" alt="S3 bucket CORS" /&gt;&lt;/p&gt;

&lt;p&gt;開啟後如同以下內容設定即可開放 &lt;code&gt;GET&lt;/code&gt; 的跨網域存取&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;CORSConfiguration&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://s3.amazonaws.com/doc/2006-03-01/&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;&amp;lt;CORSRule&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;&amp;lt;AllowedOrigin&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/AllowedOrigin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;&amp;lt;AllowedMethod&amp;gt;&lt;/span&gt;GET&lt;span class="nt"&gt;&amp;lt;/AllowedMethod&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;&amp;lt;AllowedHeader&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/AllowedHeader&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;&amp;lt;/CORSRule&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;/CORSConfiguration&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;如果要開放其他 HTTP method&amp;#8230;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;CORSConfiguration&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://s3.amazonaws.com/doc/2006-03-01/&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;&amp;lt;CORSRule&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;&amp;lt;AllowedOrigin&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/AllowedOrigin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;&amp;lt;AllowedMethod&amp;gt;&lt;/span&gt;GET&lt;span class="nt"&gt;&amp;lt;/AllowedMethod&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;&amp;lt;AllowedMethod&amp;gt;&lt;/span&gt;POST&lt;span class="nt"&gt;&amp;lt;/AllowedMethod&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;&amp;lt;AllowedMethod&amp;gt;&lt;/span&gt;PUT&lt;span class="nt"&gt;&amp;lt;/AllowedMethod&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;&amp;lt;AllowedHeader&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/AllowedHeader&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;&amp;lt;/CORSRule&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;/CORSConfiguration&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;參考資料&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html" target="_blank"&gt;http://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html&lt;/a&gt;&lt;/p&gt;
</description></item><item><title>安裝與設定 unicorn 實現佈署時 zero down time</title><pubDate>Mon, 3 Jun 2013 11:27:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-06-03/unicorn-rails-and-capistrano</guid><description>&lt;p&gt;本文章的 code 可參考公開的 pull request&lt;br/&gt;
&lt;a href="https://github.com/5fpro/cupid/pull/11/files" target="_blank"&gt;https://github.com/5fpro/cupid/pull/11/files&lt;/a&gt;&lt;br/&gt;
這是基礎到不行的設定方式，考量到 server 效能在設定上的 best practice 將會在日後持續 update 本文。&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h3&gt;安裝 gem&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Gemfile&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;capistrano-unicorn&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;unicorn&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;本文所採用的 gem 版本&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Gemfile.lock&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;capistrano&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;unicorn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;unicorn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;佈署設定&lt;/h3&gt;

&lt;p&gt;這裡的 &lt;code&gt;production.rb&lt;/code&gt; 是針對 &lt;code&gt;rails_env=production&lt;/code&gt;，而非 capistrano 中 multistage 的 production&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/unicorn/production.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;worker_processes&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;preload_app&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/tmp/unicorn.cupid.sock&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# sock 檔名可依照 app 需求設定&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;stderr_path&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;log/unicorn.error.log&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;stdout_path&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;log/unicorn.log&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tmp/pids/unicorn.pid&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;rails_env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;RAILS_ENV&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;production&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# before/after fork 可自行擴充&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;before_fork&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;after_fork&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;(也可以把上述檔案放在 &lt;code&gt;config/unicorn.rb&lt;/code&gt;)&lt;/p&gt;

&lt;h3&gt;server 上的 nginx.conf&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;nginx.conf&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;upstream&lt;/span&gt; &lt;span class="n"&gt;my_app&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;# upstream 名稱可自定&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;unix&lt;/span&gt;&lt;span class="ss"&gt;:/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;unicorn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cupid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# 這裡要和 config/unicorn/production.rb 中 listen 的設定對應&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;# passenger_enabled on; # 原本要設定 passenger 的記得要拿掉&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;# .......&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;proxy_set_header&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;Real&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;IP&lt;/span&gt; &lt;span class="vg"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;proxy_set_header&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;Forwarded&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;For&lt;/span&gt; &lt;span class="vg"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;proxy_set_header&lt;/span&gt; &lt;span class="no"&gt;Host&lt;/span&gt; &lt;span class="vg"&gt;$http_host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="ss"&gt;:/&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;my_app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# upstream 名稱&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="o"&gt;^/&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;# 這裡是 precompile 後的 assets file 路徑&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;gzip_static&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# to serve pre-gzipped version&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;expires&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;add_header&lt;/span&gt;  &lt;span class="no"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;Control&lt;/span&gt; &lt;span class="kp"&gt;public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;# .......&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;把 unicorn 重啟的 hook 掛到 deploy.rb 中&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/deploy.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;capistrano-unicorn&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;deploy:restart&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;unicorn:restart&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;done!&lt;/p&gt;

&lt;h3&gt;如何在本機測試 unicorn&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;bundle exec unicorn&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Go to http://localhost:8080&lt;/p&gt;

&lt;h3&gt;參考資料&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;更多 unicorn 可以在 cap 指令中的應用: &lt;a href="https://github.com/sosedoff/capistrano-unicorn/blob/master/lib/capistrano-unicorn/capistrano_integration.rb" target="_blank"&gt;https://github.com/sosedoff/capistrano-unicorn/blob/master/lib/capistrano-unicorn/capistrano_integration.rb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;unicorn 設定檔說明: &lt;a href="https://raw.github.com/defunkt/unicorn/master/examples/unicorn.conf.rb" target="_blank"&gt;https://raw.github.com/defunkt/unicorn/master/examples/unicorn.conf.rb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Github Blog 上說明他們自己的 unicorn 如何設定: &lt;a href="https://github.com/blog/517-unicorn" target="_blank"&gt;https://github.com/blog/517-unicorn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;其他 unicorn 設定相關教學:

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://tech.gadii.net/blog/2013/03/07/rails-deploy-ji-chu-jiao-xue/" target="_blank"&gt;http://tech.gadii.net/blog/2013/03/07/rails-deploy-ji-chu-jiao-xue/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devcenter.heroku.com/articles/rails-unicorn" target="_blank"&gt;https://devcenter.heroku.com/articles/rails-unicorn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ruby-china.org/topics/471" target="_blank"&gt;http://ruby-china.org/topics/471&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description></item><item><title>利用 Swagger 產生互動式 API 文件</title><pubDate>Sat, 4 May 2013 20:48:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-05-04/swagger-api-doc-rails</guid><description>&lt;p&gt;&lt;a href="https://developers.helloreverb.com/swagger/" target="_blank"&gt;Swagger&lt;/a&gt; 是一套由 HTML + Javascript 撰寫的 REST API 文件的框架。 (core 是以 scala 寫的)&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;從 &lt;a href="http://petstore.swagger.wordnik.com/" target="_blank"&gt;Demo 頁&lt;/a&gt; 可了解到 Swagger 不僅僅提供 API 的規格資訊，也提供互動介面讓開發者可以直接輸入參數進行測試。&lt;br/&gt;
&lt;img src="http://i.imgur.com/a5vAGKz.png" /&gt;&lt;/p&gt;

&lt;p&gt;亦支援 GET &amp;amp; POST 以外的 http method (PUT、DELETE)。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://i.imgur.com/L3c5TTt.png" /&gt;&lt;/p&gt;

&lt;p&gt;Demo 頁面的 source code 在&lt;a href="https://github.com/wordnik/swagger-ui" target="_blank"&gt; Github &lt;/a&gt;上。也可以參考 wordnik 的&lt;a href="http://developer.wordnik.com/docs.html" target="_blank"&gt; 官方正式 API 文件 &lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;API 文件內容完全是透過 ajax 取得 JSON data 產生的，因此必須提供 server 吐出符合 Swagger 文件中所定義的 JSON 格式，讓前端網頁能夠生成 API 文件的介面。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://i.imgur.com/iC3LFIL.png" border="1" style="border-color:#000000" /&gt;&lt;/p&gt;

&lt;p&gt;在 Swagger 文件中所定義的物件有:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;doc&lt;/code&gt;: 代表整份 API 文件 (&lt;a href="https://github.com/wordnik/swagger-core/wiki/Resource-Listing" target="_blank"&gt;規格文件&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resource&lt;/code&gt;: API 文件下的分類目錄 (&lt;a href="https://github.com/wordnik/swagger-core/wiki/API-Declaration" target="_blank"&gt;規格文件&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;api&lt;/code&gt;: 每一條 REST Request (&lt;a href="https://github.com/wordnik/swagger-core/wiki/API-Declaration" target="_blank"&gt;規格文件&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parameter&lt;/code&gt;: &lt;code&gt;api&lt;/code&gt; 下的每個參數 (&lt;a href="https://github.com/wordnik/swagger-core/wiki/Parameters" target="_blank"&gt;規格文件&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;model&lt;/code&gt;: 自訂的 return data type (&lt;a href="https://github.com/wordnik/swagger-core/wiki/Datatypes" target="_blank"&gt;規格文件&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;鑿於定義相當繁多且複雜，Swagger 本身有提供&lt;a href="https://github.com/wordnik/swagger-codegen/tree/master/samples/server-generator" target="_blank"&gt;部分語言的 API 文件生成後台&lt;/a&gt; (Ruby 開發者可選擇 sinatra)，讓開發者能夠花最少的時間開始使用 Swagger。&lt;/p&gt;

&lt;p&gt;但筆者仍覺得 Swagger 使開發者進入狀況的門檻仍高，因此花了點時間以 rails app 開發 Swagger json data 的管理後台生成 swagger API 文件，提供後台的 web 操作介面來產生 Swagger 的 API 文件。&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/marsz/swagger-rails" target="_blank"&gt;https://github.com/marsz/swagger-rails&lt;/a&gt;&lt;br/&gt;
Demo: &lt;a href="http://swagger.5fpro.com/" target="_blank"&gt;http://swagger.5fpro.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;功能特色:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;FB 登入/註冊，單一帳號下可建立多筆 &lt;code&gt;doc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;自訂 API 實際測試的目標網域&lt;/li&gt;
&lt;li&gt;可設定獨立網域 (FQDN)，若沒有設定系統也會自動產生一組給你用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resource&lt;/code&gt; 可排序&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;讓我們 step by step 來建立 API 文件吧。&lt;br/&gt;
範例是小弟在早期自己寫的 API，用來提供台灣縣市鄉鎮的資料庫。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;建立 &lt;code&gt;doc&lt;/code&gt;，內容如下:&lt;br/&gt;
&lt;img src="http://i.imgur.com/dM1Ori8.png" /&gt;&lt;/li&gt;
&lt;li&gt;建立 &lt;code&gt;doc&lt;/code&gt; 後，系統會提供你 API 實測時的網址格式&lt;br/&gt;
&lt;img src="http://i.imgur.com/RNsHmMx.png" /&gt;&lt;/li&gt;
&lt;li&gt;建立 &lt;code&gt;resource&lt;/code&gt; (圖略)， &lt;code&gt;resource&lt;/code&gt; 可以用來當做是管理許多 API 的目錄&lt;/li&gt;
&lt;li&gt;建立 &lt;code&gt;api&lt;/code&gt;: 選擇 http method 和 path&lt;br/&gt;
&lt;img src="http://i.imgur.com/x9wfS0U.png" /&gt;&lt;br/&gt;
若 API 參數在 path 中，可用大括號包起來，必且給予參數名稱&lt;/li&gt;
&lt;li&gt;填寫 return data type，若為某個 model 的 array 可以以圖內的格式表示&lt;br/&gt;
&lt;img src="http://i.imgur.com/5TyRs6L.png" /&gt;&lt;/li&gt;
&lt;li&gt;api path 內有參數的話，底下的 parameters 也必須增加 &lt;code&gt;parameter type&lt;/code&gt; 為 &lt;code&gt;path&lt;/code&gt; 的參數 (如圖)，名稱和大括號內對應&lt;br/&gt;
&lt;img src="http://i.imgur.com/98IsmNe.png" /&gt;&lt;/li&gt;
&lt;li&gt;有關 &lt;code&gt;model&lt;/code&gt; 的定義，可在 doc 頁找到，這裡的定義與否不會影響文件的正常顯示，有定義的話文件也會顯示出來，內容也就更完整囉&lt;br/&gt;
&lt;img src="http://i.imgur.com/F1vZR2E.png" /&gt;&lt;/li&gt;
&lt;li&gt;點擊 doc information 內的連結即可看到結果(&lt;a href="http://gaia-doc.5fpro.tw/#!/3/api_6_get_2" target="_blank"&gt;http://gaia-doc.5fpro.tw/#!/3/api_6_get_2&lt;/a&gt;)&lt;br/&gt;
&lt;img src="http://i.imgur.com/8x0rLQX.png" /&gt;&lt;/li&gt;
&lt;li&gt;當然，API 實測要有資料，必須實作 &lt;a href="http://gaia.5fpro.tw/cities/1.json" target="_blank"&gt;http://gaia.5fpro.tw/cities/1.json&lt;/a&gt; 回傳的 JSON data 才行。&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;目前的 swagger-rails 仍有許多待增加的功能:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;多人協作&lt;/li&gt;
&lt;li&gt;修改記錄&lt;/li&gt;
&lt;li&gt;自訂前端 CSS&lt;/li&gt;
&lt;li&gt;後台介面優化&lt;/li&gt;
&lt;li&gt;100% 實作 Swagger 所有支援的格式&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;最後附上筆者目前正式對外開放的 API 文件給各位參考:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="http://api-doc.thewall.tw/" target="_blank"&gt;THEWALL 這牆音樂&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gaia-doc.5fpro.tw/" target="_blank"&gt;台灣縣市鄉鎮資料庫&lt;/a&gt;, 含郵遞區號&lt;/li&gt;
&lt;li&gt;&lt;a href="http://medusa-doc.5fpro.com/" target="_blank"&gt;爬蟲系統&lt;/a&gt; (暫不開放申請)&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;筆者目前透過自己蓋的 &lt;code&gt;swagger-rails&lt;/code&gt; 用於內部溝通居多，不論在 mobile app 開發或跨語言的資料傳遞，透過 Swagger 介面的 API 實測功能，使用者很快就可以了解每條 API 的取用方式與資料格式，大大減少了溝通的成本。&lt;/p&gt;

&lt;p&gt;Swagger 參考資料:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/wordnik/swagger-core/wiki" target="_blank"&gt;Swagger Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wordnik/swagger-core/wiki/Downloads" target="_blank"&gt;Swagger Downloads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.helloreverb.com/swagger/" target="_blank"&gt;Official Site&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description></item><item><title>server 端允許 ajax cross domain 存取</title><pubDate>Sun, 28 Apr 2013 13:07:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-04-28/server-side-accept-cross-domain-ajax-request</guid><description>&lt;p&gt;在 controller 中加入以下即可允許來自 cross domain 的 ajax request&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Access-Control-Allow-Origin&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;

</description></item><item><title>Redis 在 Passenger 重起後出現 'reconnect to Redis after forking' 的錯誤訊息</title><pubDate>Sat, 13 Apr 2013 22:02:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-04-13/redis-reconnect-after-fork</guid><description>&lt;p&gt;自 &lt;code&gt;redis&lt;/code&gt; 升級，每次透過 &lt;code&gt;capistrano&lt;/code&gt; 佈署後，連線 server 都會噴出 &amp;#8220;Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.&amp;#8221; 的錯誤訊息。&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;原因在於 &lt;code&gt;redis&lt;/code&gt; 的 &lt;a href="https://github.com/redis/redis-rb" target="_blank"&gt;client gem&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;因此必須在每次 passenger restart 後，也讓 redis client 進行重啓。可參考以下，必須於 initializer 或 application.rb 中執行。&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;PhusionPassenger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="no"&gt;PhusionPassenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:starting_worker_process&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;forked&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;forked&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="no"&gt;Redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:host&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:port&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;除了 &lt;code&gt;redis&lt;/code&gt; 之外，其他透過 redis 應用的 gem 也都會有類似的問題，例如 &lt;code&gt;resque&lt;/code&gt;、&lt;code&gt;redis-store&lt;/code&gt;、&lt;code&gt;redis-object&lt;/code&gt;、&lt;code&gt;sidekiq&lt;/code&gt; 等。&lt;/p&gt;
</description></item><item><title>新版的 git (1.7 以上) 在 merge 時預設不開編輯器的設定</title><pubDate>Tue, 9 Apr 2013 02:02:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-04-09/git-merge-no-edit-default</guid><description>&lt;p&gt;打開你的 shell rc 例如 &lt;code&gt;~/.zshrc&lt;/code&gt; 或 &lt;code&gt;~/bashrc&lt;/code&gt;&lt;br/&gt;
插入以下&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;export GIT_MERGE_AUTOEDIT=no&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;!-- more --&gt;


&lt;p&gt;之後 merge &amp;#8211;no-ff 的指令就都會預設用 auto message 做 commit 啦&lt;br/&gt;
如果想要強制編輯時，可以用 &amp;#8211;edit 參數&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;git merge branch_name --no-ff --edit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;



</description></item><item><title>修正 IE 無法透過 cross-domain AJAX 取得 JSON 物件</title><pubDate>Fri, 29 Mar 2013 22:52:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-03-29/ie-jquery-ajax-jsonp-n-cross-domain-n-cache-control-public</guid><description>&lt;p&gt;controller 中的 &lt;code&gt;respond_to&lt;/code&gt; 可用來 return 指定的 format 供 JS 取用 API 資料&lt;br/&gt;
但很不幸的 IE 9 以下在透過 jquery 中的 getJSON 無法取得 return 的 json 物件。&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;server 端的 action&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Access-Control-Allow-Origin&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;expires_in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:public&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="vi"&gt;@data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SomeModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:json&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:xml&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;client 端的 javascript&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://apihost.com/products.json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;jsonp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;結果:  IE9 以下不 work，其他瀏覽器沒問題(生氣)&lt;/p&gt;

&lt;p&gt;解決此問題的方法必須例用 jquery jsonp callback 的方式達到目的即可&lt;br/&gt;
因此 server 端的 response 的 content-type 必須是 javascript (見 &lt;a href="http://d.pr/i/66d0" target="_blank"&gt;此圖&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;server 端寫法&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Access-Control-Allow-Origin&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;expires_in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:public&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="vi"&gt;@data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SomeModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:json&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:xml&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:json&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:callback&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:callback&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;client 端的 javascript&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://apihost.com/products.js?callback=?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;搞定!!!&lt;/p&gt;

&lt;p&gt;server 端其他寫法的補充:&lt;/p&gt;

&lt;p&gt;開啟 cross-domain 的 ajax request&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Access-Control-Allow-Origin&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;開啟 cache-control 為 public:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;expires_in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:public&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;



</description></item><item><title>我寫的 gem - venus 簡介</title><pubDate>Wed, 13 Mar 2013 13:12:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2013-03-13/rubygems-venus</guid><description>&lt;p&gt;因受到了&lt;a href="http://railsapps.github.com/rails-composer/" target="_blank"&gt; rails composor &lt;/a&gt; 的影響，決定也來寫一個客製化的 rails generator。&lt;br/&gt;
但後來又覺得只能在開新專案用的話，使用頻率也不太高&amp;#8230;&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;鑿於在許多專案中，總是為了要安裝某些 gem 而必須再回去翻寫過專案中的 code 或上官網找範例 code 做 copy/paste + 修改，於是我決定寫一個 generator 來設定這些常用的 gem，僅需要如同 rails composor 一樣回答一些問題就可以把所有的設定弄到好。&lt;/p&gt;

&lt;p&gt;因此 venus 因應而生&lt;/p&gt;

&lt;p&gt;安裝: &lt;a href="https://rubygems.org/gems/venus" target="_blank"&gt;https://rubygems.org/gems/venus&lt;/a&gt;  &lt;br/&gt;
源碼: &lt;a href="https://github.com/marsz/venus" target="_blank"&gt;https://github.com/marsz/venus&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;以下逐一介紹各個指令&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;專案初始化設定，例如移除 public/index.html，安裝必要的 gem 例如分頁用的 &lt;code&gt;kminari&lt;/code&gt;，剛 new 好的 rails 專案適合執行此指令。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:mysql&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;設定 mysql，包含從 &lt;code&gt;Gemfile&lt;/code&gt; 安裝 mysql2，設定 &lt;code&gt;database.yml&lt;/code&gt; 以及 &lt;code&gt;database.yml.example&lt;/code&gt;，最後再將 &lt;code&gt;config/database.yml&lt;/code&gt; 加到 .gitignore 中。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:paginate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;單獨安裝分頁用的 gem - &lt;code&gt;kminari&lt;/code&gt;，也會問你要不要產生客製化的 view 出來。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:simple_form&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;view 使用 form 必備的 &lt;a href="https://github.com/plataformatec/simple_form" target="_blank"&gt;simple_form&lt;/a&gt;，預設會產生 bootstrap wrapper 的設定檔。也會詢問是否要順便安裝 &lt;a href="https://github.com/ryanb/nested_form" target="_blank"&gt;nested_form&lt;/a&gt;，安裝 nested_form 需要在 js 中 require gem 裡面包好的 JS，所以也會詢問 require code 和 example code 要放的檔案路徑。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:settingslogic&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;gem - &lt;a href="https://github.com/binarylogic/settingslogic" target="_blank"&gt;&lt;code&gt;settingslogic&lt;/code&gt;&lt;/a&gt;。可以將多個 yml 的設定檔放在此 gem 所讀取的 yaml 下，使其能夠容易管理。此 generator 同時也會產生 .example 檔以及加入 .yml 到 .gitignore 下。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:rspec&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安裝並且設定 &lt;code&gt;rspec&lt;/code&gt;，並且移除 test 目錄，在 &lt;code&gt;config/application.rb&lt;/code&gt; 中設定 generate controller 時，不自動產生 assets files 和 helper。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:devise&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安裝並且設定 scope 為 user 的 devise gem。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:omniauth&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;會先檢查是否有安裝 settingslogic 以及 devise，然後再安裝 omniauth，過程中會詢問 facebook / twitter / github 登入的安裝與否。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:redis&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安裝並且設定 redis client gem &lt;a href="https://github.com/redis/redis-rb" target="_blank"&gt;redis-rb&lt;/a&gt; 。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:aws&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安裝並且設定 Amazon &lt;a href="https://github.com/aws/aws-sdk-ruby" target="_blank"&gt;官方的 ruby client &lt;/a&gt;。過程中會先檢查 settingslogic，並且將 api key 和 secret 存到其中。最後也會詢問否需要順便安裝 Amazon Simple Email Service (SES)，用來發 email。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:carrierwave&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安裝並且設定 carrierwave，其中包含 rmagick 進行縮圖，以及 fog 將檔案上傳至S3。過程中會安裝 aws-sdk，所以也會順便詢問 SES 的設定 :p。最後會產生一個 &lt;code&gt;venus_uploader.rb&lt;/code&gt; 做為範例。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:jqueryui&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安裝 jquery ui 的 gem。其中會詢問是否要安裝 datepicker，包含產生 trigger 用的 js 範例 code。gem 的 參考連結 =&gt; &lt;a href="https://github.com/joliss/jquery-ui-rails" target="_blank"&gt;https://github.com/joliss/jquery-ui-rails&lt;/a&gt;。 (若有要安裝 datepicker 的話，也會詢問語系)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:chosen&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安裝 &lt;a href="https://github.com/tsechingho/chosen-rails" target="_blank"&gt;chosen-rails&lt;/a&gt; 並且提供 trigger chosen 的範例 js code。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails generate venus:bootstrap&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安裝 &lt;code&gt;twitter bootstrap&lt;/code&gt; ，包含 gem 設定、 assets require，最後產生範例 layout 檔於 &lt;code&gt;app/views/layouts/&lt;/code&gt; 下。內建提供 &lt;a href="http://wrapbootstrap.com/preview/WB0F35928" target="_blank"&gt;unicorn admin&lt;/a&gt; 的版型套用，蓋後台超爽 XD&lt;/p&gt;

&lt;h1&gt;TODOs&lt;/h1&gt;

&lt;p&gt;對於此 gem 未來將會逐漸加入我自己寫的 best practice :p 也望各位大大能不吝指教或回報 bug :D&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sidekiq : 強大的 background job gem&lt;/li&gt;
&lt;li&gt;unicorn : 配合 capistrano 讓佈署時可以 zero down time&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/airblade/paper_trail" target="_blank"&gt;paper_trail&lt;/a&gt; : 對 model 進行版本控制的 gem&lt;/li&gt;
&lt;/ul&gt;

</description></item><item><title>自動化產生 ER 圖的 rubygem</title><pubDate>Tue, 13 Nov 2012 05:39:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-11-13/auto-generate-erd-graph</guid><description>&lt;p&gt;參考連結:&lt;br/&gt;
1. 官網 : &lt;a href="http://rails-erd.rubyforge.org/" target="_blank"&gt;http://rails-erd.rubyforge.org/&lt;/a&gt;&lt;br/&gt;
2. 相關教學 : &lt;a href="http://zool.me/rails/2010/12/29/Rails-generate-entity-relationship-diagram-projects/" target="_blank"&gt;http://zool.me/rails/2010/12/29/Rails-generate-entity-relationship-diagram-projects/&lt;/a&gt;&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h3&gt;系統需求&lt;/h3&gt;

&lt;p&gt;MAC OS 請先安裝 &lt;code&gt;brew&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;安裝 Graphviz&lt;/h3&gt;

&lt;h5&gt;MAC OS&lt;/h5&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;brew install cairo pango graphviz&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;若無法順利安裝可至 &lt;a href="http://www.graphviz.org/Download_macos.php" target="_blank"&gt;graphviz for MAC OS download&lt;/a&gt; 頁面下載對應的系統，直接打開 finder 以 window 介面安裝&lt;/p&gt;

&lt;h5&gt;Ubuntu&lt;/h5&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;sudo aptitude install graphviz&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Rails 設定&lt;/h3&gt;

&lt;h5&gt;Gemfile&lt;/h5&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rails-erd&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;生成 ERD&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;erd&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;生成的 ERD 會在專案目錄下的 erd.pdf&lt;/p&gt;
</description></item><item><title>Rubygems 處理 Amazon Web Service (AWS) EC2</title><pubDate>Fri, 9 Nov 2012 13:55:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-11-09/rubygeems-for-aws-ec2</guid><description>&lt;p&gt;參考: &lt;a href="https://github.com/grempe/amazon-ec2" target="_blank"&gt;https://github.com/grempe/amazon-ec2&lt;/a&gt;&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h3&gt;安裝設定&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Gemfile&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;amazon-ec2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;AWS&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/aws.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;development&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;default&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:access_key_id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;abcdabcd&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:secret_access_key&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;abcdabcd&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:host&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;ap-southeast-1.ec2.amazonaws.com&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;test&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;code&gt;access_key_id&lt;/code&gt; 和 &lt;code&gt;secret_access_key&lt;/code&gt; 可至 &lt;a href="https://portal.aws.amazon.com/gp/aws/developer/account/index.html?action=access-key" target="_blank"&gt;AWS Security Credentials&lt;/a&gt; 查看&lt;br/&gt;
&lt;code&gt;host&lt;/code&gt; 則是目標 region 所對應的 endpoint，對應表可至 &lt;a href="https://github.com/garnaat/missingcloud/blob/master/aws.json#L372" target="_blank"&gt;https://github.com/garnaat/missingcloud/blob/master/aws.json#L372&lt;/a&gt; 查看&lt;/p&gt;

&lt;p&gt;養成好習慣, 請勿將 yaml 檔 commit 進去&amp;#8230;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;.gitignore&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/aws.yml.example&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# to see region and host mapping :&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;#   https://github.com/garnaat/missingcloud/blob/master/aws.json#L372&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;development&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;default&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:access_key_id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:secret_access_key&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;:host&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;test&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="l-Scalar-Plain"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;使用方法&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;初始化&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;example.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/config/aws.yml&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;ec2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;AWS&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EC2&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:access_key_id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:access_key_id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:secret_access_key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:secret_access_key&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:server&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:host&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;ul&gt;
&lt;li&gt;取得 instance 列表&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;exmaple.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;describe_instances&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# instances[&amp;quot;reservationSet&amp;quot;][&amp;quot;item&amp;quot;] 才會取得 array&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;ul&gt;
&lt;li&gt;取得所有 snapshots (自己 create 的)&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;exmaple.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;snapshots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;describe_snapshots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:owner&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;self&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# snapshots[&amp;quot;snapshotSet&amp;quot;][&amp;quot;item&amp;quot;] 才會取得 array&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;ul&gt;
&lt;li&gt;取得所有 volumes&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;exmaple.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;volumes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;describe_volumes&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# volumes[&amp;quot;volumeSet&amp;quot;][&amp;quot;item&amp;quot;] 才會取得 array&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;ul&gt;
&lt;li&gt;建立 snapshot, 必須先取得 volume id&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;example.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;volume_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;volumeSet&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;item&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;volumeId&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_snapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:volume_id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;volume_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:description&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;my snapshot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;ul&gt;
&lt;li&gt;建立某個 instance 的 snapshot, 有 instance id 的情況下&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;example.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;instance_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;i-abcd&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;volume_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;describe_volumes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;volumeSet&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;item&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;attachmentSet&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;item&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;instanceId&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;instance_id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;instanceId&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;instance_id&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;volumeId&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_snapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:volume_id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;volume_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:description&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;foo bar&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;snapshotId&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 新的 snapshot id&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;ul&gt;
&lt;li&gt;更多可參考 API: &lt;a href="https://github.com/grempe/amazon-ec2/tree/master/lib/AWS/EC2" target="_blank"&gt;https://github.com/grempe/amazon-ec2/tree/master/lib/AWS/EC2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description></item><item><title>IE 瀏覽器讀取 css 檔案的 selector (4096)限制</title><pubDate>Sun, 16 Sep 2012 23:24:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-09-16/ie-css-selector-limitation-4096</guid><description>&lt;p&gt;IE 瀏覽器在讀取每個 css 檔案時，不能超過 4096 個 selector，超過的都會被忽略&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;註: &lt;code&gt;.foo .bar { .... }&lt;/code&gt; 代表一個 selector&lt;br/&gt;
&lt;code&gt;stackoverflow&lt;/code&gt; 也有相關問題: &lt;a href="http://bit.ly/QiuvNC" target="_blank"&gt;http://bit.ly/QiuvNC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;由於 &lt;code&gt;twitter boostrap&lt;/code&gt; 以及其應用外掛的流行，要破 4096 個 selector 是輕而易舉的事，要測試你所使用的瀏覽器有沒有支援超過，可以&lt;a href="http://marc.baffl.co.uk/browser_bugs/css-selector-limit/" target="_blank"&gt;看這個網頁&lt;/a&gt;，若顯示的背景為紅色代表不支援，綠色表示沒問題。&lt;/p&gt;

&lt;p&gt;解決此問題最快的辦法就是把 css 分檔案就行了，rails 的 assets precompile 的 css 中若混雜著 bootstrap 之類的套件就會很容易超過此限制，只要把這些不會被修改的套件掛上 CDN 或分不同檔案 precompile 就可以處理了。&lt;/p&gt;
</description></item><item><title>自動隱藏 iPhone safari 的網址列</title><pubDate>Sun, 9 Sep 2012 13:46:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-09-09/hide-address-bar-iphone-safari</guid><description>&lt;p&gt;在 &lt;code&gt;html&lt;/code&gt; 的 &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; 裡面加上&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='html'&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;viewport&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;width=device-width, initial-scale=1.0, minimum-scale=1.0&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;apple-mobile-web-app-capable&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;yes&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;apple-mobile-web-app-status-bar-style&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;black&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;參考來源: &lt;a href="http://stackoverflow.com/questions/4759818/how-to-hide-the-address-bar-of-a-webpage-in-android" target="_blank"&gt;http://stackoverflow.com/questions/4759818/how-to-hide-the-address-bar-of-a-webpage-in-android&lt;/a&gt;&lt;/p&gt;
</description></item><item><title>取得獨一無二的 session id</title><pubDate>Sun, 9 Sep 2012 11:32:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-09-09/unique-session-id</guid><description>&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_options&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;參考連結: &lt;a href="http://stackoverflow.com/questions/4824829/finding-the-session-id-in-rails-3" target="_blank"&gt;http://stackoverflow.com/questions/4824829/finding-the-session-id-in-rails-3&lt;/a&gt;&lt;/p&gt;
</description></item><item><title>rake db 的 tasks 整理</title><pubDate>Mon, 3 Sep 2012 15:38:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-09-03/about-rake-db-tasks</guid><description>&lt;p&gt;善用 rails rake 內建的 DB tasks 進行資料庫操作&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;&lt;code&gt;rake db:migrate&lt;/code&gt; - 執行 db/migrate 中還沒跑過的 migrations&lt;br/&gt;
&lt;code&gt;rake db:migrate VERSION=12341234&lt;/code&gt; - 針對設定的 migrations 版本執行&lt;br/&gt;
&lt;code&gt;rake db:migrate:redo&lt;/code&gt; - 重跑目前最新的 migration&lt;br/&gt;
&lt;code&gt;rake db:migrate:redo STEP=3&lt;/code&gt; - 重跑目前最新的三個 migration&lt;br/&gt;
&lt;code&gt;rake db:rollback&lt;/code&gt; - 還原跑過最新的 migration&lt;br/&gt;
&lt;code&gt;rake db:rollback STEP=3&lt;/code&gt; - 還原跑過最新三個的 migration&lt;br/&gt;
&lt;code&gt;rake db:create&lt;/code&gt; - 建立 database&lt;br/&gt;
&lt;code&gt;rake db:drop&lt;/code&gt; - 刪除整個 database&lt;br/&gt;
&lt;code&gt;rake db:schema:dump&lt;/code&gt; - 從目前 database 中實際的 schema 建立 db/schema.rb&lt;br/&gt;
&lt;code&gt;rake db:schema:load&lt;/code&gt; - 從 db/schema.rb 中把 schema 建立到 databse 中&lt;br/&gt;
&lt;code&gt;rake db:structure:dump&lt;/code&gt; - 從目前 database 中實際的 schema 輸出到 db/structure.sql&lt;br/&gt;
&lt;code&gt;rake db:reset&lt;/code&gt; - 合體的 task ( db:drop =&gt; db:create =&gt; db:schema:load)&lt;/p&gt;

&lt;p&gt;另外安裝了 &lt;a href="https://github.com/ludicast/yaml_db" target="_blank"&gt;&lt;code&gt;yaml_db&lt;/code&gt;&lt;/a&gt; 後，可以透過以下兩個指令把資料庫的資料做 export/import (不包含 schema)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rake db:data:dump&lt;/code&gt; - 把資料輸出到 db/data.yml&lt;br/&gt;
&lt;code&gt;rake db:data:load&lt;/code&gt; - 把資料從 db/data.yml 輸入到 database 中&lt;/p&gt;
</description></item><item><title>layout 檔案的命名</title><pubDate>Tue, 21 Aug 2012 15:16:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-08-21/rails-layout-file-naming</guid><description>&lt;p&gt;今天發現 &lt;code&gt;layout&lt;/code&gt; 檔 (views/layouts) 的命名是不能亂來的 ~XD&lt;br/&gt;
嘗試用 dash 命名 (例如 foo-bar.html.haml) 的結果造成 haml 無法被 parsing&lt;br/&gt;
所以還是乖一點用小寫英文和 underline 吧 :p&lt;/p&gt;
</description></item><item><title>我的 Sublime Text 2 設定</title><pubDate>Sun, 19 Aug 2012 21:46:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-08-19/sublimetext-shortcuts-and-configurations-for-sass-erb-rubytest</guid><description>&lt;p&gt;最後更新: 2013/3/31&lt;br/&gt;
&lt;a href="http://www.sublimetext.com/" target="_blank"&gt;Sublime&lt;/a&gt; 是一套強大的文字編輯器，和我用過的 Textmate 類似，但功能更為強大 XD&lt;br/&gt;
以下是我的設定範例。&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h1&gt;實用快速鍵&lt;/h1&gt;

&lt;p&gt;參考: &lt;a href="https://gist.github.com/1207002" target="_blank"&gt;https://gist.github.com/1207002&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;自定快速鍵&lt;/h1&gt;

&lt;p&gt;以下視個人喜好而定:&lt;/p&gt;

&lt;p&gt;上方選單 -&gt; Sublime Text 2 -&gt; Preferences -&gt; Key Bindings Default&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;  // 快速顯示目前檔案所在的目錄樹下
&lt;/span&gt;&lt;span class='line'&gt;  { "keys": ["ctrl+super+r"], "command": "reveal_in_side_bar" },
&lt;/span&gt;&lt;span class='line'&gt;  // 找 swap_line_up 出來改, 可以換置上下行
&lt;/span&gt;&lt;span class='line'&gt;  { "keys": ["alt+up"], "command": "swap_line_up" },
&lt;/span&gt;&lt;span class='line'&gt;  { "keys": ["alt+down"], "command": "swap_line_down" },
&lt;/span&gt;&lt;span class='line'&gt;  // 找 duplicate_line 出來改, 可以快速複製一行
&lt;/span&gt;&lt;span class='line'&gt;  { "keys": ["super+alt+down"], "command": "duplicate_line" },
&lt;/span&gt;&lt;span class='line'&gt;  { "keys": ["super+alt+up"], "command": "duplicate_line" },
&lt;/span&gt;&lt;span class='line'&gt;  // 找 auto_complete 出來改
&lt;/span&gt;&lt;span class='line'&gt;  { "keys": ["super+."], "command": "auto_complete" },
&lt;/span&gt;&lt;span class='line'&gt;  // 刪除一整列, 記得要 search "super+d" 把其他的 key binding 砍掉, 或者可以用別的 key binding
&lt;/span&gt;&lt;span class='line'&gt;  { "keys": ["super+d"], "command": "run_macro_file", "args": {"file": "Packages/Default/Delete Line.sublime-macro"} },&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h1&gt;安裝好後設定 link&lt;/h1&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" ~/bin/subl
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;sudo ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" /usr/bin/subl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;code&gt;ubuntu&lt;/code&gt; 的話可以用&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;sudo ln -s ~/Applications/Sublime\ Text\ 2/sublime_text /usr/bin/subl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;shell link，編輯 &lt;code&gt;~/.bashrc&lt;/code&gt; 或 &lt;code&gt;~/.zshrc&lt;/code&gt; (看你用的是哪一個 shell)&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;export EDITOR="/usr/local/bin/subl -w"&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h1&gt;setting 檔 &lt;/h1&gt;

&lt;p&gt;&lt;code&gt;command + ,&lt;/code&gt; 出現的檔案&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;{
&lt;/span&gt;&lt;span class='line'&gt;  "color_scheme": "Packages/Color Scheme - Default/Twilight.tmTheme",
&lt;/span&gt;&lt;span class='line'&gt;  "font_size": 18.0,
&lt;/span&gt;&lt;span class='line'&gt;  "tab_size": 2,
&lt;/span&gt;&lt;span class='line'&gt;  "translate_tabs_to_spaces": true,  
&lt;/span&gt;&lt;span class='line'&gt;  "highlight_line": true,
&lt;/span&gt;&lt;span class='line'&gt;  "highlight_modified_tabs": true
&lt;/span&gt;&lt;span class='line'&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;(PS: 年紀大了所以用字體 size 用 18 XD)&lt;br/&gt;
(PS2: tab 設定隨個人/公司喜好)&lt;/p&gt;

&lt;h1&gt;安裝 package control&lt;/h1&gt;

&lt;p&gt;用於快速安裝其他 package 的好工具&lt;/p&gt;

&lt;p&gt;參考 &lt;a href="http://wbond.net/sublime_packages/package_control/installation" target="_blank"&gt;http://wbond.net/sublime_packages/package_control/installation&lt;/a&gt;&lt;br/&gt;
ctrl+` 開啟 command line 後輸入:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;import urllib2,os; pf='Package Control.sublime-package'; ipp=sublime.installed_packages_path(); os.makedirs(ipp) if not os.path.exists(ipp) else None; urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler())); open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read()); print 'Please restart Sublime Text to finish installation'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;重啟 sublime, &lt;code&gt;command+shift+p&lt;/code&gt; 輸入 install 看到 &lt;code&gt;Package Control: Install Package&lt;/code&gt; 即可透過此功能安裝其他 package&lt;/p&gt;

&lt;h1&gt;安裝 sass/scss/haml 檔案支援&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;安裝 &lt;code&gt;package control&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;command+shift+p&lt;/code&gt; 輸入 &lt;code&gt;install&lt;/code&gt; 選 &lt;code&gt;Package Control: Install Package&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;鍵入 &lt;code&gt;sass&lt;/code&gt; 選第一個安裝即可&lt;/li&gt;
&lt;li&gt;重複 &lt;code&gt;2.&lt;/code&gt;, 鍵入 &lt;code&gt;haml&lt;/code&gt; 選第一個安裝即可&lt;/li&gt;
&lt;/ol&gt;


&lt;h1&gt;安裝 ERB 檔案的編輯強化&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;安裝 &lt;code&gt;package control&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;command+shift+p&lt;/code&gt; 輸入 &lt;code&gt;install&lt;/code&gt; 選 &lt;code&gt;Package Control: Install Package&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;鍵入 &lt;code&gt;erb snippets&lt;/code&gt; 選第一個安裝即可&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;參考&lt;a href="https://github.com/matthewrobertson/ERB-Sublime-Snippets" target="_blank"&gt;官方文件&lt;/a&gt; 有快速 block template 可產生。&lt;/p&gt;

&lt;p&gt;例如在 .erb 檔中，打 &lt;code&gt;er&lt;/code&gt; 然後再按 &lt;code&gt;tab&lt;/code&gt; 鍵就會生成 &lt;code&gt;&amp;lt;% %&amp;gt;&lt;/code&gt;。&lt;/p&gt;
</description></item><item><title>omniauth 登入後的 redirect 設定</title><pubDate>Fri, 10 Aug 2012 14:08:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-08-10/omniauth-redirect-after-login</guid><description>&lt;p&gt;我們曾在 &lt;a href="http://rubyist.marsz.tw/blog/2012-01-10/callbacks-of-devise-after-sign-in-or-sign-out/"&gt;Devise callbacks&lt;/a&gt; 中，描述如何在登入後自定 redirect。這次則是在 omniauth 進行 open id 驗證時就先把 redirect 當參數先丟。&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;參考 &lt;a href="https://github.com/intridea/omniauth/issues/218"&gt;官方作法&lt;/a&gt;&lt;br/&gt;
利用 &lt;code&gt;origin&lt;/code&gt; 參數即可在 open id 驗證後進行 redirect&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;config/routes.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/auth/facebook&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:facebook_login&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;app/views/xxx.erb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# view 或 controller 下&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;facebook_login_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:origin&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/url/for/redirect&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# 即 &amp;quot;/auth/facebook?origin=/url/for/redirect&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;若 &lt;code&gt;devise&lt;/code&gt; 中已經透過 application_controller.rb 的 &lt;code&gt;after_sign_in_path_for&lt;/code&gt; 處理登入後的 redirect 時，則可以透過 &lt;code&gt;request.env['omniauth.origin']&lt;/code&gt; 取得 origin 參數的內容。&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;app/controllers/application_controller.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;after_sign_in_path_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;omniauth.origin&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;root_path&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;



</description></item><item><title>devise 的 user 登入免驗證密碼</title><pubDate>Thu, 9 Aug 2012 17:15:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-08-09/devise-user-without-validate_password</guid><description>&lt;p&gt;&lt;code&gt;Devise&lt;/code&gt; 加上 &lt;code&gt;Omniauth&lt;/code&gt; (或其他 Open ID 登入機制) 時，資料庫的密碼欄位可能會需要為空值，因此可在 user 的 model 中覆寫 &lt;code&gt;password_required?&lt;/code&gt; (為 public method) 即可。&lt;/p&gt;

&lt;!-- more --&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;app/models/user.rb&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;password_required?&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;facebook_id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;該範例之邏輯為，有 facebook id 時密碼欄位可為空值。&lt;/p&gt;
</description></item><item><title>讀書心得: 刻意練習(6)</title><pubDate>Tue, 7 Aug 2012 13:42:00 +0800</pubDate><guid isPermaLink="false">http://rubyist.marsz.tw/blog/2012-08-07/reading-deliberate-practice-6</guid><description>&lt;p&gt;最後一篇分享了 XD 本篇主要摘要刻意練習對創意的發展&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h3&gt;我們對創意的誤解&lt;/h3&gt;

&lt;p&gt;一般我們認為創意之所以會有，乃是來自於 &lt;code&gt;1. 靈光乍現&lt;/code&gt; &lt;code&gt;2. 置身領域之外的旁觀者&lt;/code&gt;，
事實上這兩點都是不太正確的。任何突破性的創意產生之前，都是當事者下了多年的苦工後才有的。研究人員找出五百多首作曲，來自於個作曲家的第一部成名作或曠世巨作，發現其中只有三件作品是在作曲家職涯的前十年完成，而這三件作品完成的時間也是在第八年和第九年。而這樣的數據足以說明前述的 &lt;code&gt;十年法則&lt;/code&gt;。&lt;/p&gt;

&lt;h3&gt;創意的正解&lt;/h3&gt;

&lt;h5&gt;知識越多創新越多&lt;/h5&gt;

&lt;p&gt;在十年法則的漫長時間下，創作者做的活動大多是吸取專精知識，這些活動絕對是該領域密集而且深度的薰陶，即使沒有指導者，創新者本身也股強烈的動力，盡可能的學習與該領域相關的事物。&lt;/p&gt;

&lt;h5&gt;創意是孕育出來的&lt;/h5&gt;

&lt;p&gt;其實我們可以從現代科技中發現，這些創新都是既有事物的改良和延伸，透過卓越的洞見得以實現。如果不是因為了解過去的成就，這些創新肯定不可能實現。因此我們可確定&lt;code&gt;靈光乍現是來自多時的思索和研究&lt;/code&gt;，絕非偶然、也不是無中生有。&lt;/p&gt;

&lt;h3&gt;打造創新組織四大關鍵&lt;/h3&gt;

&lt;h5&gt;動機與熱情&lt;/h5&gt;

&lt;p&gt;刻意練習不是輕鬆的過程，沒有熱情支持難以持續。因此創新者本身是熱切接受自身領域的薰陶，以及其相關的深度知識。&lt;/p&gt;

&lt;h5&gt;文化變革&lt;/h5&gt;

&lt;p&gt;只要是組織 (2人以上) 都離不開文化的議題，而文化變革必須從上位者本身做起，只要公司的&amp;#8221;長&amp;#8221;字輩認為公司文化沒問題，它就永遠不可能改變。&lt;/p&gt;

&lt;h5&gt;傳達需求&lt;/h5&gt;

&lt;p&gt;組織想要有所創新，就得讓其中的每個人都了解哪種創新最有價值，有了方向才能夠進行深度的心智模型建立、投入大量心力，領導者在這裡扮演重要角色。&lt;/p&gt;

&lt;h5&gt;賦予自由&lt;/h5&gt;

&lt;p&gt;當組織內的每個人都被注入動機以及明確方向時，接下來需要注意的就是給予發揮空間，刻意練習強調的是自發性，組織在此要扮演推手的角色，而非造成限制。&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;身為網路工作者，又是工程師。在讀完本書後，小弟首先做的就是調整作息~XD 一改平日睡到十點後才醒來的習慣，想辦法在早上擠出 1~2 小時做最困難的工作 (通常都是 coding 或 debug)，我設定給自己的關鍵指標就是開發所花的時間: 每天早上這 1~2 小時能完成多少工作。&lt;/p&gt;

&lt;p&gt;在這樣的過程中剛開始是很痛苦，其實早起感覺都沒睡飽，注意力也難以集中，但震盪期大概持續一個月左右就適應了。習慣後慢慢發現另一個重要的指標: 專注力，程式開發是很注重當下的專心度，因此開始用一些方式提高專注力，關掉手機以及電腦的各種通知等，用高度的感知以及後設認知檢視自己在這段時間內的專注力是否有提昇。&lt;/p&gt;

&lt;p&gt;有了一定程度的專注力後，又發現了另一個指標: 英文資料理解速度。程式開發遇到問題經常要上孤狗，而資料多半是英文，因此能夠花越少的時間孤狗，相對就能夠花越多時間在開發上，效率自然會提昇。&lt;/p&gt;

&lt;p&gt;如此循環進行，發現不斷找到新的評估指標，然後持續提昇。目前小弟正在磨練的另一項技能是養成寫 blog 的習慣，將自己曾經解決的問題以及累積的知識得以文件保存，除此之外，身為工程師仍有許多能力必須提昇，例如和別人溝通時是否能以最精簡的方式傳達，專案執行前的目標設定是否足夠嚴謹、達成率是否足夠等。刻意練習概念所帶給我的，是變得更了解這些技能學習過程的運作原理，進而更能掌握自己各方面能力的提升。&lt;/p&gt;
</description></item></channel></rss>