<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">

 <title>Richard Huang</title>
 
 <link href="http://www.huangzhimin.com/" />
 <updated>2012-02-27T23:52:29-08:00</updated>
 <id>http://www.huangzhimin.com/</id>
 <author>
   <name>Richard Huang</name>
   <email>flyerhzm@gmail.com</email>
 </author>

 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/richard-huang" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="richard-huang" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bloglines.com/sub/http://feeds.feedburner.com/richard-huang" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2Frichard-huang" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><entry>
   <title>passenger with http_gzip_static_module</title>
   <link href="http://www.huangzhimin.com/2012/02/27/passenger-with-http-gzip-static-module/" />
   <updated>2012-02-27T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2012/02/27/passenger-with-http-gzip-static-module</id>
   <content type="html">&lt;p&gt;Rails 3.1 has been released for a long time, asset pipeline becomes more
and more popular, I also upgraded my rails website.&lt;/p&gt;

&lt;p&gt;I used nginx + passenger for my rails projects, but nginx only supports
dynamic gzip support (compress in runtime), there is a
http_gzip_static_module for nginx, which can make full use of rails
asset pipeline.&lt;/p&gt;

&lt;p&gt;I don't like the way to customize my Nginx installation during passenger
installation, I found there is a [pull request] to add
http_gzip_static_module, so I changed to source code of passenger gem,
then installed nginx as default. :-)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[1]:[https://github.com/FooBarWidget/passenger/pull/35]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/CmdBMrm4sOv4o1wOcPctF6NZT6U/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CmdBMrm4sOv4o1wOcPctF6NZT6U/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/CmdBMrm4sOv4o1wOcPctF6NZT6U/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CmdBMrm4sOv4o1wOcPctF6NZT6U/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XMvZs8uZmKk:r5JnbnNEyWU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XMvZs8uZmKk:r5JnbnNEyWU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=XMvZs8uZmKk:r5JnbnNEyWU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XMvZs8uZmKk:r5JnbnNEyWU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=XMvZs8uZmKk:r5JnbnNEyWU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XMvZs8uZmKk:r5JnbnNEyWU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/XMvZs8uZmKk" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>rake arguments</title>
   <link href="http://www.huangzhimin.com/2011/12/13/rake-arguments/" />
   <updated>2011-12-13T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/12/13/rake-arguments</id>
   <content type="html">&lt;p&gt;Long ago I began to write some rake tasks, it's simple but doesn't have
an instruction about how to add arguments to a rake task. What I did
before is to use ruby environment variables.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;As you seen, I have to set the global environment variable to pass the
arguement to a rake task.&lt;/p&gt;

&lt;p&gt;But there is another way to pass the arguments to rake task via []&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;It looks like the difference between hash arguments and normal arguments.&lt;/p&gt;

&lt;p&gt;Both of them have disadvantage:&lt;/p&gt;

&lt;p&gt;ENV arguments also changes the system env variables
normal arguments do not make sense when calling, difficult to remember
the meanings of arguments.&lt;/p&gt;

&lt;p&gt;Both work fine, it depends on you to use which one.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/teSSEk4a5pzDxEXvSGWsoL7ivQI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/teSSEk4a5pzDxEXvSGWsoL7ivQI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/teSSEk4a5pzDxEXvSGWsoL7ivQI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/teSSEk4a5pzDxEXvSGWsoL7ivQI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=LANhYCe6IyU:AhF12-OrG14:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=LANhYCe6IyU:AhF12-OrG14:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=LANhYCe6IyU:AhF12-OrG14:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=LANhYCe6IyU:AhF12-OrG14:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=LANhYCe6IyU:AhF12-OrG14:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=LANhYCe6IyU:AhF12-OrG14:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/LANhYCe6IyU" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>passenger with redis</title>
   <link href="http://www.huangzhimin.com/2011/12/12/passenger-with-redis/" />
   <updated>2011-12-12T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/12/12/passenger-with-redis</id>
   <content type="html">&lt;p&gt;Today I encountered an issue that passenger forks too many workers
than what we set (6) on qa servers. I used strace, the passenger worker
is blocked by failed to writing to a socket, like&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;fd 13 is a socket.&lt;/p&gt;

&lt;p&gt;I also tried netstat and found the status for some redis socket
connections are CLOSE_WAIT.&lt;/p&gt;

&lt;p&gt;So I judged this is the problem the ruby redis clients are not closed
correctly. This reminds me that passenger fork() nature, I checked our
source codes, unfortunately, we didn't do anything special for passenger
fork.&lt;/p&gt;

&lt;p&gt;This is the &lt;a href="https://github.com/ezmobius/redis-rb/wiki/redis-rb-on-Phusion-Passenger"&gt;link&lt;/a&gt; tells you how to close the redis connection after
passenger forks a worker. After deploy the new codes to qa servers,
passenger never forks more workers than we expected. But the workers
still hang up according strace result, that means some workers keep
inactive status, they won't be able to handle any requests. Wooops...&lt;/p&gt;

&lt;p&gt;I looked through the redis-rb source codes, we used redis 2.0.5, it
didn't handle TIMEOUT error and always retry writing to redis.
Fortunately, the latest redis version is 2.2.2 and it already fixed this
issue, retry 3 times, if still failed, the release the connection.&lt;/p&gt;

&lt;p&gt;Now it works fine, no unexpected additional passenger workers and no
unexpected inactive workers.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/KiPDNX3mkytLKzENd7IK0Hc8JKI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KiPDNX3mkytLKzENd7IK0Hc8JKI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/KiPDNX3mkytLKzENd7IK0Hc8JKI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KiPDNX3mkytLKzENd7IK0Hc8JKI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=sLBv2gaALio:CEEs1LfBV2Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=sLBv2gaALio:CEEs1LfBV2Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=sLBv2gaALio:CEEs1LfBV2Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=sLBv2gaALio:CEEs1LfBV2Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=sLBv2gaALio:CEEs1LfBV2Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=sLBv2gaALio:CEEs1LfBV2Y:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/sLBv2gaALio" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>avoid committing git conflicts</title>
   <link href="http://www.huangzhimin.com/2011/11/14/avoid-committing-git-conflicts/" />
   <updated>2011-11-14T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/11/14/avoid-committing-git-conflicts</id>
   <content type="html">&lt;p&gt;I made a mistake when merging branch last week, I forgot to remove a
conflict syntax "&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD" and push it to remote repository. It
breaks other one's development. So stupid to make such mistake.&lt;/p&gt;

&lt;p&gt;To avoid making such mistake anymore, I write a git hook
.git/hooks/pre-commit to check conflict syntax "&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;" and "&gt;&gt;&gt;&gt;&gt;&gt;"&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;It will prevent you from committing conflicts.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/t19VhcOHTGdhrm8H08Nsv0OoWsQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/t19VhcOHTGdhrm8H08Nsv0OoWsQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/t19VhcOHTGdhrm8H08Nsv0OoWsQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/t19VhcOHTGdhrm8H08Nsv0OoWsQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=EIs594C3Now:d_pKWcyLfXI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=EIs594C3Now:d_pKWcyLfXI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=EIs594C3Now:d_pKWcyLfXI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=EIs594C3Now:d_pKWcyLfXI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=EIs594C3Now:d_pKWcyLfXI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=EIs594C3Now:d_pKWcyLfXI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/EIs594C3Now" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>after_commit</title>
   <link href="http://www.huangzhimin.com/2011/11/06/after_commit/" />
   <updated>2011-11-06T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2011/11/06/after_commit</id>
   <content type="html">&lt;p&gt;We are using RabbitMQ as our message queue system, ruby client is
workling. This week we encountered a strange issue, we create a
notification, and define an after_create callback to ask workling to
find that notification and then push the notification to twitter or
facebook, it works fine except that sometimes it will raise an error
said "can't find the notification with the specified ID"&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;It's wierd the notification_id is passed to NotificationWorker, that
means the notification is already created, the notification is supposed
to be existed.&lt;/p&gt;

&lt;p&gt;After talking with MySQL DBA, we find the problem is the find sql is
executed before insert transaction is committed.&lt;/p&gt;

&lt;p&gt;Let me describe it step by step.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Notification sends "Transaction Begin" command&lt;/li&gt;
&lt;li&gt;Notification sends "INSERT" command&lt;/li&gt;
&lt;li&gt;Notification gets "next sequence value" as new object id&lt;/li&gt;
&lt;li&gt;Notification sends "new object id" to NotificationWorker&lt;/li&gt;
&lt;li&gt;NotificationWorker sends "SELECT" command to find notification object&lt;/li&gt;
&lt;li&gt;Notification sends "Transaction Commit" command&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;As you seen, at step 5, the new notification is not existed in the mysql
database yet, so the error "Not found" will be raised.&lt;/p&gt;

&lt;p&gt;To solve this issue, we can use after_commit callback.&lt;/p&gt;

&lt;p&gt;In rails 2.x, we should install after_commit gem, in rails 3.x,
after_commit callback is supported by default.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;So Notification asks NotificationWorker to run only after the
transaction is committed.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/US0kH0MrrQ8gNr7pxnZlqwKqzfU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/US0kH0MrrQ8gNr7pxnZlqwKqzfU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/US0kH0MrrQ8gNr7pxnZlqwKqzfU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/US0kH0MrrQ8gNr7pxnZlqwKqzfU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=DWARuFDcONc:C5u-BB4z-OQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=DWARuFDcONc:C5u-BB4z-OQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=DWARuFDcONc:C5u-BB4z-OQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=DWARuFDcONc:C5u-BB4z-OQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=DWARuFDcONc:C5u-BB4z-OQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=DWARuFDcONc:C5u-BB4z-OQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/DWARuFDcONc" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>reset_counter in rails</title>
   <link href="http://www.huangzhimin.com/2011/10/31/reset_counter-in-rails/" />
   <updated>2011-10-31T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2011/10/31/reset_counter-in-rails</id>
   <content type="html">&lt;p&gt;I thought reset_counter method is to reset a counter_cache column to be
0, but it is not. After trying several times, I finally realize that
reset_counter is to update the value of counter_cache column to the
exact count of associations. The usecase of reset_counter is when you
add the counter_cache in migration and update the counter_cache value,
like&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;it will add comments_count column to posts table, and calculate the
comments count for each post, and set it to posts' comments_count
column.&lt;/p&gt;

&lt;p&gt;I didn't find a method to reset the counter_cache column to be 0, why?
Because counter_cache is used to cache the association count, it will be
incremented and decremeneted automatically, you should never reset it 0.
If you find you need to reset counter_cache to 0, that means it's a
wrong usage of counter_cache.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/96NxuxX8UjBqoNRmr1_canKsooM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/96NxuxX8UjBqoNRmr1_canKsooM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/96NxuxX8UjBqoNRmr1_canKsooM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/96NxuxX8UjBqoNRmr1_canKsooM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=K883SdPUDIk:3I4oVEnZ8I0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=K883SdPUDIk:3I4oVEnZ8I0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=K883SdPUDIk:3I4oVEnZ8I0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=K883SdPUDIk:3I4oVEnZ8I0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=K883SdPUDIk:3I4oVEnZ8I0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=K883SdPUDIk:3I4oVEnZ8I0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/K883SdPUDIk" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>use rspec filter to speed up tests</title>
   <link href="http://www.huangzhimin.com/2011/10/21/rspec-filter/" />
   <updated>2011-10-21T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2011/10/21/rspec-filter</id>
   <content type="html">&lt;p&gt;Rspec 2 introduce a very efficient way to test only one test or one test
suit, it's filter_run.&lt;/p&gt;

&lt;p&gt;You should first add filter_run in rspec/spec_helper.rb&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;Then you can tell rspec to test only one test you are focused by&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;rspec will only test this spec, :focus =&gt; true can be applied on
describe/context as well.&lt;/p&gt;

&lt;p&gt;One problem is that if there is no :focus =&gt; true on your tests, rspec
will do nothing, but most of time we are expecting to test all specs if
no focus is true, so you should add a line to spec_helper as well.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;As the name implies, rspec will test all specs if no focus filter.&lt;/p&gt;

&lt;p&gt;Another you may interest that you can also define filter_run_excluding&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;rspec will run all specs except what specs are marked as slow.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ucRfEg66A6UE_sCFtRYx41IxIBc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ucRfEg66A6UE_sCFtRYx41IxIBc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ucRfEg66A6UE_sCFtRYx41IxIBc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ucRfEg66A6UE_sCFtRYx41IxIBc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=e852CiSntuM:9Fm5Y6Tv9nw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=e852CiSntuM:9Fm5Y6Tv9nw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=e852CiSntuM:9Fm5Y6Tv9nw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=e852CiSntuM:9Fm5Y6Tv9nw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=e852CiSntuM:9Fm5Y6Tv9nw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=e852CiSntuM:9Fm5Y6Tv9nw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/e852CiSntuM" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>rubykaigi presentation</title>
   <link href="http://www.huangzhimin.com/2011/07/17/rubykaigi-presentation/" />
   <updated>2011-07-17T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2011/07/17/rubykaigi-presentation</id>
   <content type="html">&lt;p&gt;My presentation in RubyKaigin 2011 today.&lt;/p&gt;

&lt;div style="width:425px" id="__ss_8617337"&gt;&lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/flyerhzm/rails-best-practicesrubykaigi" title="Rails best practices_rubykaigi"&gt;Rails best practices_rubykaigi&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse8617337" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=railsbestpracticesrubykaigi-110717075124-phpapp02&amp;stripped_title=rails-best-practicesrubykaigi&amp;userName=flyerhzm" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse8617337" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=railsbestpracticesrubykaigi-110717075124-phpapp02&amp;stripped_title=rails-best-practicesrubykaigi&amp;userName=flyerhzm" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding:5px 0 12px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/flyerhzm"&gt;Richard Huang&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;


&lt;p&gt;and the video is here: &lt;a href="http://www.ustream.tv/recorded/16051491"&gt;http://www.ustream.tv/recorded/16051491&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eIq8BNsf2KBOBB3OdFJIx86cwSg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eIq8BNsf2KBOBB3OdFJIx86cwSg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eIq8BNsf2KBOBB3OdFJIx86cwSg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eIq8BNsf2KBOBB3OdFJIx86cwSg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=RsiOA3vX5mE:WzszW2lwVVw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=RsiOA3vX5mE:WzszW2lwVVw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=RsiOA3vX5mE:WzszW2lwVVw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=RsiOA3vX5mE:WzszW2lwVVw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=RsiOA3vX5mE:WzszW2lwVVw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=RsiOA3vX5mE:WzszW2lwVVw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/RsiOA3vX5mE" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>beijing ruby线下活动</title>
   <link href="http://www.huangzhimin.com/2011/03/27/beijing-ruby-event/" />
   <updated>2011-03-27T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2011/03/27/beijing-ruby-event</id>
   <content type="html">&lt;p&gt;周日在北京的ruby线下活动的ppt&lt;/p&gt;

&lt;div style="width:425px" id="__ss_7409659"&gt; &lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/flyerhzm/rails-best-practices-7409659" title="使用Rails best practices做代码审查"&gt;使用Rails best practices做代码审查&lt;/a&gt;&lt;/strong&gt; &lt;object id="__sse7409659" width="425" height="355"&gt; &lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=railsbestpractices-110327215428-phpapp02&amp;stripped_title=rails-best-practices-7409659&amp;userName=flyerhzm" /&gt; &lt;param name="allowFullScreen" value="true"/&gt; &lt;param name="allowScriptAccess" value="always"/&gt; &lt;embed name="__sse7409659" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=railsbestpractices-110327215428-phpapp02&amp;stripped_title=rails-best-practices-7409659&amp;userName=flyerhzm" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt; &lt;/object&gt; &lt;div style="padding:5px 0 12px"&gt; View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/flyerhzm"&gt;Richard Huang&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;


&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/XqfHKiDl_Iosqgz5vL2k72fQU8I/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XqfHKiDl_Iosqgz5vL2k72fQU8I/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/XqfHKiDl_Iosqgz5vL2k72fQU8I/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XqfHKiDl_Iosqgz5vL2k72fQU8I/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=WlK3h6VrMdc:SBHDkF_JM_o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=WlK3h6VrMdc:SBHDkF_JM_o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=WlK3h6VrMdc:SBHDkF_JM_o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=WlK3h6VrMdc:SBHDkF_JM_o:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=WlK3h6VrMdc:SBHDkF_JM_o:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=WlK3h6VrMdc:SBHDkF_JM_o:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/WlK3h6VrMdc" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Upgrade Mongoid - Multiple databases</title>
   <link href="http://www.huangzhimin.com/2011/03/22/upgrade-mongoid-multiple-database/" />
   <updated>2011-03-22T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2011/03/22/upgrade-mongoid-multiple-database</id>
   <content type="html">&lt;p&gt;My recent post &lt;a href="http://www.huangzhimin.com/2011/01/14/use-different-mongodb-instances-in-mongoid/"&gt;Use different mongodb instances in mongoid&lt;/a&gt; tells you how to use multiple databases, it looks good, but mongoid began to support multiple databases itself from mongoid.2.0.0.rc.1, much better than my hack.&lt;/p&gt;

&lt;p&gt;It's really easy to use, first, you should define multiple databases in mongoid.yml like&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l yaml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;As you seen, besides the common database param, I have defined a new param databases, you should define the mongo instance name with database and host name, and of course, you can define as many mongo instances as you need.&lt;/p&gt;

&lt;p&gt;Then, you can choose which mongo instance to use in mongoid model.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;set_database method tells mongoid that the model will use another mongo instance instead of the main mongo instance, here we use the name other_mongo_instance_name which should exactly be the same with the name defined in mongoid.yml. If you don't say anything, it will use the main_mongo_instance.&lt;/p&gt;

&lt;p&gt;So all the users data will be stored to other_mongo_instance_name, and the other data will be stored to main_mongo_instance. Great!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/9_u2aOnzu_hnr25phUUVEmfNKPc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9_u2aOnzu_hnr25phUUVEmfNKPc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/9_u2aOnzu_hnr25phUUVEmfNKPc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9_u2aOnzu_hnr25phUUVEmfNKPc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=NbTQzbVe02o:PDIYnJpU85Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=NbTQzbVe02o:PDIYnJpU85Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=NbTQzbVe02o:PDIYnJpU85Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=NbTQzbVe02o:PDIYnJpU85Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=NbTQzbVe02o:PDIYnJpU85Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=NbTQzbVe02o:PDIYnJpU85Y:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/NbTQzbVe02o" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Upgrade Mongoid - update_attribute</title>
   <link href="http://www.huangzhimin.com/2011/03/21/upgrade-mongoid-update_attribute/" />
   <updated>2011-03-21T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2011/03/21/upgrade-mongoid-update_attribute</id>
   <content type="html">&lt;p&gt;Before mongoid 2.0.0.rc.6, there is no update_attribute method for Mongoid::Document, it makes me unhappy. As in ActiveRecord world, I always use update_attribute to change one attribute and use update_attributes to change two or more attributes.&lt;/p&gt;

&lt;p&gt;It's a good news that mongoid introduces the update_attribute method from 2.0.0.rc.6, now I can follow my practice in mongoid.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/3O9ESyZCEGJLDsgc3_EvKqtuyX4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3O9ESyZCEGJLDsgc3_EvKqtuyX4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/3O9ESyZCEGJLDsgc3_EvKqtuyX4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3O9ESyZCEGJLDsgc3_EvKqtuyX4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=KKzTDqTjRys:wBYscT3oZ_U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=KKzTDqTjRys:wBYscT3oZ_U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=KKzTDqTjRys:wBYscT3oZ_U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=KKzTDqTjRys:wBYscT3oZ_U:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=KKzTDqTjRys:wBYscT3oZ_U:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=KKzTDqTjRys:wBYscT3oZ_U:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/KKzTDqTjRys" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Upgrade Mongoid - Many to many association</title>
   <link href="http://www.huangzhimin.com/2011/03/08/upgrade-mongoid-many-to-many-associations/" />
   <updated>2011-03-08T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/03/08/upgrade-mongoid-many-to-many-associations</id>
   <content type="html">&lt;p&gt;Before mongoid 2.0.0.rc1, there is no default support for many to many association. So we use join document (aka join table in relational database) to implement the many to many association.&lt;/p&gt;

&lt;p&gt;For example, we have two documents users and accounts, one user has many accounts and one account contains many users, to establish the many to many relationship between users and accounts, we create a new document named user_accounts, the document looks like&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l javascript -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;and the models are defined as follows&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;Are you familiar with it, it's what activerecord did for many to many association.&lt;/p&gt;

&lt;p&gt;I'm glad that mongoid began to support many to many association after mongoid 2.0.0.rc1, the new syntax is "referenes_and_referenced_in_many".&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;We don't need the join document any more. The implementation of mongoid is different with activerecord, it uses array attribute to store the relationship at both sides. Like&lt;/p&gt;

&lt;p&gt;These are user documents&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l javascript -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;And these are account documents&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l javascript -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;As mongodb support the Array type, it is really easy to maintain the many to many relationship.&lt;/p&gt;

&lt;p&gt;Btw, if you use&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;before, you will receive a runtime error. You should use&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;instead.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/GB2dDW--Tv63hf3ZzlnZEb5QFTY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GB2dDW--Tv63hf3ZzlnZEb5QFTY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/GB2dDW--Tv63hf3ZzlnZEb5QFTY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GB2dDW--Tv63hf3ZzlnZEb5QFTY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Rw1cdqFe1s8:vJhEGvoQCI4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Rw1cdqFe1s8:vJhEGvoQCI4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Rw1cdqFe1s8:vJhEGvoQCI4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Rw1cdqFe1s8:vJhEGvoQCI4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Rw1cdqFe1s8:vJhEGvoQCI4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Rw1cdqFe1s8:vJhEGvoQCI4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/Rw1cdqFe1s8" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Upgrade Mongoid - Hash arguments for group</title>
   <link href="http://www.huangzhimin.com/2011/03/01/upgrade-mongoid-hash-arguments-for-group/" />
   <updated>2011-03-01T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/03/01/upgrade-mongoid-hash-arguments-for-group</id>
   <content type="html">&lt;p&gt;You will receive a warning for the group method call after upgrading mongoid.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;exactly this is because mongo gem changes the group method definition.&lt;/p&gt;

&lt;p&gt;Before&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;After&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;This is the usage of hash arguments, it makes the group calling more readable.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/PWst5MVR4fkDv7sscP4Iq2FkyXs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PWst5MVR4fkDv7sscP4Iq2FkyXs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/PWst5MVR4fkDv7sscP4Iq2FkyXs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PWst5MVR4fkDv7sscP4Iq2FkyXs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=4nSk_mWeD-U:TEhV8gWTeoQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=4nSk_mWeD-U:TEhV8gWTeoQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=4nSk_mWeD-U:TEhV8gWTeoQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=4nSk_mWeD-U:TEhV8gWTeoQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=4nSk_mWeD-U:TEhV8gWTeoQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=4nSk_mWeD-U:TEhV8gWTeoQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/4nSk_mWeD-U" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Upgrade Mongoid - Default Type for Field</title>
   <link href="http://www.huangzhimin.com/2011/01/28/upgrade-mongoid-default-type-for-field/" />
   <updated>2011-01-28T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/01/28/upgrade-mongoid-default-type-for-field</id>
   <content type="html">&lt;p&gt;If you have watched the episode about &lt;a href="http://railscasts.com/episodes/238-mongoid"&gt;mongoid&lt;/a&gt; from railscast, ryanb removed the default type String for field, like&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;can be written as&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;but it is not valid from mongoid.2.0.0.rc.1 again, the default type of field is changed from String to Object, that means we should explicitly set the type for each field.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/g2jwBnKMoXGIqdrudpklo-jmVXk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/g2jwBnKMoXGIqdrudpklo-jmVXk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/g2jwBnKMoXGIqdrudpklo-jmVXk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/g2jwBnKMoXGIqdrudpklo-jmVXk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=FJhDN4EW12M:UBmNuyowl5c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=FJhDN4EW12M:UBmNuyowl5c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=FJhDN4EW12M:UBmNuyowl5c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=FJhDN4EW12M:UBmNuyowl5c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=FJhDN4EW12M:UBmNuyowl5c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=FJhDN4EW12M:UBmNuyowl5c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/FJhDN4EW12M" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Upgrade Mongoid - Write Tests First</title>
   <link href="http://www.huangzhimin.com/2011/01/27/upgrade-mongoid-write-tests-first/" />
   <updated>2011-01-27T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/01/27/upgrade-mongoid-write-tests-first</id>
   <content type="html">&lt;p&gt;Mongoid is one of the popular Object Document Mappings between Ruby and Mongo, and it is still evolving. We began to use mongoid 2.0.0.beta.20 several weeks ago, the author of mongoid @durran said he wanted to release the 2.0.0 last week (As you know 2.0.0 is still not released yet, but he really did a lot of awesome work), so we tried the version 2.0.0.rc.6 to prepare upgrading to final 2.0.0.&lt;/p&gt;

&lt;p&gt;I'm working on upgrading mongoid from 2.0.0.beta.20 to 2.0.0.rc.6 these days. I'm willing to write several posts to share my experience about upgrading.&lt;/p&gt;

&lt;p&gt;At the first post, I just want you keep in mind that &lt;strong&gt;don't do any upgrading before you write tests for your models&lt;/strong&gt;. There are many api changes between mongoid 2.0.0.beta.20 and 2.0.0.rc.6, I can't imagine how to upgrade without tests, as our project has almost 30 models and 100 view pages, I can't check the models and views one by one. Luckily, we have built many rspec tests for models and cucumber tests.&lt;/p&gt;

&lt;p&gt;It's expected that many test failures raised after upgrading, if I fixed all the failures, the job to upgrade is complete.&lt;/p&gt;

&lt;p&gt;I have to say I like such upgrading job, I read the source codes of mongoid, checked git logs, sometimes thought why they made such changes, and always learned a lot from reading source codes. :-)&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/O3psSyJLS6TBAafgfc27Otnbfjo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/O3psSyJLS6TBAafgfc27Otnbfjo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/O3psSyJLS6TBAafgfc27Otnbfjo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/O3psSyJLS6TBAafgfc27Otnbfjo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=fy_RZxDpzT4:kYxCxOsGYIA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=fy_RZxDpzT4:kYxCxOsGYIA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=fy_RZxDpzT4:kYxCxOsGYIA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=fy_RZxDpzT4:kYxCxOsGYIA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=fy_RZxDpzT4:kYxCxOsGYIA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=fy_RZxDpzT4:kYxCxOsGYIA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/fy_RZxDpzT4" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Migrate Custom Blog to Jekyll and Disqus</title>
   <link href="http://www.huangzhimin.com/2011/01/20/migrate-custom-blog-to-jekyll-and-disqus/" />
   <updated>2011-01-20T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/01/20/migrate-custom-blog-to-jekyll-and-disqus</id>
   <content type="html">&lt;p&gt;I wrote my blog system by myself about 3 years ago, using rails. It's good, but not cool enough, I just need some changes to make my blog better. After googling, I found jekyll, which is a simple, blog aware, static site generator, that means no databases and much less resources wanted, sounds great.&lt;/p&gt;

&lt;h2&gt;Build a Blog by Jekyll&lt;/h2&gt;

&lt;p&gt;Then I began to build the new blog system by jekyll two weeks ago. It's really easy to install and use, check the document &lt;a href="https://github.com/mojombo/jekyll"&gt;here&lt;/a&gt;. As you know, I'm a developer, of course I install the pygments for code highlight. But there are several limitations for the default jekyll.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;no category section on sidebar.&lt;/li&gt;
&lt;li&gt;no archive section on sidebar.&lt;/li&gt;
&lt;li&gt;no categroy page, which lists the posts in that category.&lt;/li&gt;
&lt;li&gt;no monthly archive page, which list posts by month.&lt;/li&gt;
&lt;li&gt;no comments, yep, it generates a static website.&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;can't display liquid codes on post.&lt;/strike&gt;(Use literal tag to display liquid codes)&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Like rails, jekyll supports plugins and extensions so that we can extend it as we want. Originally I planed to host my blog on github, but I found github doesn't support any plugins and extensions, it only supports the default official jekyll. Bad news, I have to host it on my own server with jekyll extensions, it's not a big problem.&lt;/p&gt;

&lt;p&gt;The best extesion of jekyll I found is &lt;a href="https://github.com/rfelix/jekyll_ext"&gt;jekyll_ext&lt;/a&gt;, it provides a really flexible way to extend jekyll. The author also shares his jekyll &lt;a href="https://github.com/rfelix/my_jekyll_extensions"&gt;extensions&lt;/a&gt; using jekyll_ext. I forked the &lt;a href="http://disqus.com"&gt;extensions&lt;/a&gt; to fix the generation of archive page and add the archive section on sidebar.&lt;/p&gt;

&lt;p&gt;OK, let me show how to fix the above limitation with my forked extension.&lt;/p&gt;

&lt;p&gt;1. category section on sidebar.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l html -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;2. archive section on sidebar.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l html -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;3. category page, add a layout &lt;code&gt;category_index.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l html -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;4. monthly archive page, add a layout &lt;code&gt;archive_monthly.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l html -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;5. comments, hmmm...it's impossible for jekyll to provide comments functionality, but I guess you know the web service &lt;a href="http://disqus.com"&gt;disqus&lt;/a&gt; which provides an online comment system. You can get two javascripts after you creating an forum on disqus, one for posting/displaying comments, the other is to dispaly comments count for each post. The following is the javascript to post/display comments.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l html -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;And the javascript to display comments count.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l html -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;&lt;strike&gt;
6. can't display liquid codes. I found this limitation while I'm writing this post, it's impossible to display raw liquid codes, as liquid always try to execute each liquid code. I have to write a custom tag raw to solve this issue.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;So you can use the raw tag to escape all the liquid codes as you want.
&lt;/strike&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can get the source code of my blog system on &lt;a href="https://github.com/flyerhzm.github.com"&gt;github&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Migrate Legacy Data&lt;/h2&gt;

&lt;p&gt;OK, the new blog system is complete, but what about the old blog posts
and comments? I want to migrate them to the new system.&lt;/p&gt;

&lt;p&gt;I'm a developer, so it's not too difficult for to migrate old data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migrate old posts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Like the common blog system, the old post is saved as html format. After working on several projects on github, I start to love markdown, so I decide to convert all the old html posts to markdown format. There is a project named &lt;a href="https://github.com/xijo/reverse-markdown"&gt;reverse-markdown&lt;/a&gt; to do this job, I also forked it to handle code highlight (before I used syntaxhighlighter, now is &lt;code&gt;{% highlight language %}...{% endhighlight %}&lt;/code&gt;), here is the &lt;a href="https://gist.github.com/788039"&gt;script&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then I began to migrate old posts&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;I run the above codes in rails console, the above codes translate the post title and category name from Chinese to English, convert the body of post from html to markdown, and then save them under temp directory.&lt;/p&gt;

&lt;p&gt;After running the codes, there are a lot of posts generated under temp directory, I just copy them to the _post directory in the new blog system, then the posts migration is complete. Cool!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migrate old comments&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Migrating comments is a bit difficult, it takes me a few days to play with disqus api. Luckily disqus provides a api console, I really like it.&lt;/p&gt;

&lt;p&gt;The following codes are what I used to migrate comments to disqus.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;The aboved codes are also run in rails console, it works as follows.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;checks if the new post url existed.&lt;/li&gt;
&lt;li&gt;if so, it reads or creates a thread, one thread on disqus is corresponding to one post url in blog system.&lt;/li&gt;
&lt;li&gt;then create a post on disque, one post on disqus is corresponding to one comment in blog system.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;There is a problem, in disqus, email of comment author can't be empty, but in my old blog system the email of comment user can be empty, so I have use "anonymous@gmail.com" instead. This is the only limitation when I migrate old comments.&lt;/p&gt;

&lt;p&gt;Everything works well. I love my new blog system.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Pc-lfKgJoz5dmdFYYSV6rjCRFbk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Pc-lfKgJoz5dmdFYYSV6rjCRFbk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Pc-lfKgJoz5dmdFYYSV6rjCRFbk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Pc-lfKgJoz5dmdFYYSV6rjCRFbk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=0dbSks_0xbo:2xEIazNcja0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=0dbSks_0xbo:2xEIazNcja0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=0dbSks_0xbo:2xEIazNcja0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=0dbSks_0xbo:2xEIazNcja0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=0dbSks_0xbo:2xEIazNcja0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=0dbSks_0xbo:2xEIazNcja0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/0dbSks_0xbo" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Construct Nested Hash in Ruby</title>
   <link href="http://www.huangzhimin.com/2011/01/18/construct-nested-hash-in-ruby/" />
   <updated>2011-01-18T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/01/18/construct-nested-hash-in-ruby</id>
   <content type="html">&lt;p&gt;I just received a post request on rails-bestpractices.com from hlxwell, he recommend "Nested hash simple initialization."&lt;/p&gt;

&lt;p&gt;Change From&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;To&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;Frankly speeking, I don't agree with him.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I don't think he needs the too much level nested hash, he may reconsider his design of data structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If he really needs such nested hash, he should use the more graceful way instead&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/EJ2GmnCg61dMlm1JLPgdKpQUCg4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EJ2GmnCg61dMlm1JLPgdKpQUCg4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/EJ2GmnCg61dMlm1JLPgdKpQUCg4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EJ2GmnCg61dMlm1JLPgdKpQUCg4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=FAp9Tcjj47M:4KlyTDkescA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=FAp9Tcjj47M:4KlyTDkescA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=FAp9Tcjj47M:4KlyTDkescA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=FAp9Tcjj47M:4KlyTDkescA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=FAp9Tcjj47M:4KlyTDkescA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=FAp9Tcjj47M:4KlyTDkescA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/FAp9Tcjj47M" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Use different mongodb instances in mongoid</title>
   <link href="http://www.huangzhimin.com/2011/01/14/use-different-mongodb-instances-in-mongoid/" />
   <updated>2011-01-14T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/01/14/use-different-mongodb-instances-in-mongoid</id>
   <content type="html">&lt;p&gt;By default, we save all the collections in one mongodb instance, or replicate/shard all of them into different mongodb instances. But what if saving a special collection into one mongodb instance, and the other collections into the other mongodb instance?&lt;/p&gt;

&lt;p&gt;This is what I need to do with a mongoid project several weeks before.  In common we just define a mongodb instance in the &lt;code&gt;config/mongoid.yml&lt;/code&gt;, yep, you can define only one instance for one environment just like activerecord, the define the different mongodb instance in model.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;change the &lt;code&gt;AD_DB_HOST&lt;/code&gt;, &lt;code&gt;AD_DB_PORT&lt;/code&gt;, &lt;code&gt;AD_DB_NAME&lt;/code&gt; and &lt;code&gt;AD_COLLECTION_NAME&lt;/code&gt; with your mongodb configuration, the following is my configuration,&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;and it would be better move these configurations into a config file.&lt;/p&gt;

&lt;p&gt;Now when saving or reading the ads collection, it uses &lt;code&gt;localhost:27018/ad_development&lt;/code&gt;, and the other collections use &lt;code&gt;localhost:27017/project_development&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/yxiV8CK13lFPOMw-fTnKPx8byj0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yxiV8CK13lFPOMw-fTnKPx8byj0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/yxiV8CK13lFPOMw-fTnKPx8byj0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yxiV8CK13lFPOMw-fTnKPx8byj0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Oliab7qYtqY:s30d_uEcwuw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Oliab7qYtqY:s30d_uEcwuw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Oliab7qYtqY:s30d_uEcwuw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Oliab7qYtqY:s30d_uEcwuw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Oliab7qYtqY:s30d_uEcwuw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Oliab7qYtqY:s30d_uEcwuw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/Oliab7qYtqY" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Drop tmp collections in Mongodb</title>
   <link href="http://www.huangzhimin.com/2011/01/06/drop-tmp-collections-in-mongodb/" />
   <updated>2011-01-06T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2011/01/06/drop-tmp-collections-in-mongodb</id>
   <content type="html">&lt;p&gt;I'm trying mongodb map/reduce functionality with mongoid these days. I find there is a &lt;code&gt;tmp.mr.mapreduce_ddd_ddd&lt;/code&gt; collection created after each map/reduce operation, it's ok that these tmp collections are used to hold output of map/reduce operation.&lt;/p&gt;

&lt;p&gt;From mongodb document, it's said the temp collections will be cleaned up when the client connection closes or when explicitly dropped. But I never see these temp collections are dropped, when I print &lt;code&gt;show collections&lt;/code&gt;, there are too many temp collections annoyed me, I decided to drop these temp collections explicitly.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l javascript -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;It finds all the namespaces whose names contain tmp.mr, if so, drop the collections.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/v3ZdbHo2THq1fAtMRns43Rv1hcw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/v3ZdbHo2THq1fAtMRns43Rv1hcw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/v3ZdbHo2THq1fAtMRns43Rv1hcw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/v3ZdbHo2THq1fAtMRns43Rv1hcw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=q_xiekOLITA:bDCySmA9Dao:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=q_xiekOLITA:bDCySmA9Dao:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=q_xiekOLITA:bDCySmA9Dao:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=q_xiekOLITA:bDCySmA9Dao:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=q_xiekOLITA:bDCySmA9Dao:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=q_xiekOLITA:bDCySmA9Dao:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/q_xiekOLITA" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>JQuery Plugin Template</title>
   <link href="http://www.huangzhimin.com/2010/12/20/jquery-plugin-template/" />
   <updated>2010-12-20T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/12/20/jquery-plugin-template</id>
   <content type="html">&lt;p&gt;JQuery is one of the most important javascript framework I used, besides
default jquery apis, I use a lot of jquery plugins to improve the web
interactive, such as auto complete, dropdown menu, chart and so on.&lt;/p&gt;

&lt;p&gt;I will be likely to write some jquery plugins or hack others' jquery
plugins, The following is the template for a jquery plugin that I
learned from "jQuery 1.4 Plugin Development"&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l javascript -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;the structure &lt;code&gt;(function($) {...})(jQuery)&lt;/code&gt; can protected the conflict
of $ sign which is used by other javascript framework.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$.extend({}, defaults, options)&lt;/code&gt; provides a flexible way to tweak your
plugin, options can override defaults, but not change the value of
defaults.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;return this.each(function() {...})&lt;/code&gt; promises your plugin functions are
chainable, like the default jquery apis.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/tJABZiqSEkab4PA6puj6g5VAI0Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tJABZiqSEkab4PA6puj6g5VAI0Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/tJABZiqSEkab4PA6puj6g5VAI0Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tJABZiqSEkab4PA6puj6g5VAI0Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=zbgi0eq1AKM:EXyslTLYbag:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=zbgi0eq1AKM:EXyslTLYbag:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=zbgi0eq1AKM:EXyslTLYbag:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=zbgi0eq1AKM:EXyslTLYbag:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=zbgi0eq1AKM:EXyslTLYbag:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=zbgi0eq1AKM:EXyslTLYbag:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/zbgi0eq1AKM" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>盛大创新院分享</title>
   <link href="http://www.huangzhimin.com/2010/08/12/innovation-institute-grand-share/" />
   <updated>2010-08-12T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/08/12/innovation-institute-grand-share</id>
   <content type="html">&lt;p&gt;昨天去盛大创新院做分享，主要是介绍我目前正在做的网站，&lt;a href="http://rails-bestpractices.com"&gt;rails-bestpractices.com&lt;/a&gt;&lt;/p&gt;

&lt;div style="width:425px" id="__ss_4946169"&gt;&lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/flyerhzm/rails-bestpracticescom" title="Rails bestpractices.com"&gt;Rails bestpractices.com&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse4946169" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rails-bestpractices-com-100811082516-phpapp02&amp;stripped_title=rails-bestpracticescom&amp;userName=flyerhzm" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse4946169" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rails-bestpractices-com-100811082516-phpapp02&amp;stripped_title=rails-bestpracticescom&amp;userName=flyerhzm" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding:5px 0 12px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/flyerhzm"&gt;Richard Huang&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;


&lt;p&gt;盛大创新院还是很不错的地方，只可惜昨天他们一些做rails的牛人都在开会，失去了一个被拍砖的机会&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/gHnVkm8kcPp5sw948Fn6o_ymSYU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/gHnVkm8kcPp5sw948Fn6o_ymSYU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/gHnVkm8kcPp5sw948Fn6o_ymSYU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/gHnVkm8kcPp5sw948Fn6o_ymSYU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XHRd42yviJc:l5N83N07yiw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XHRd42yviJc:l5N83N07yiw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=XHRd42yviJc:l5N83N07yiw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XHRd42yviJc:l5N83N07yiw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=XHRd42yviJc:l5N83N07yiw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XHRd42yviJc:l5N83N07yiw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/XHRd42yviJc" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>将table的数据导出为csv</title>
   <link href="http://www.huangzhimin.com/2010/07/20/export-table-data-to-csv/" />
   <updated>2010-07-20T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/07/20/export-table-data-to-csv</id>
   <content type="html">&lt;p&gt;项目中经常会有这样的usecase，把一个table中的数据导出为csv，用fastercsv这个gem可以快速完成这个功能。&lt;/p&gt;

&lt;p&gt;首先放一个导出csv的链接&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;然后在controller中生成相应的csv，并发送给用户&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;其中用FasterCSV快速创建好csv数据，再通过send_data发送给客户端就可以了&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/SJeyp_abVQpEXQh1d_R-f7NkHbw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SJeyp_abVQpEXQh1d_R-f7NkHbw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/SJeyp_abVQpEXQh1d_R-f7NkHbw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SJeyp_abVQpEXQh1d_R-f7NkHbw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Eqln_uq9at4:nCZNos5-dwY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Eqln_uq9at4:nCZNos5-dwY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Eqln_uq9at4:nCZNos5-dwY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Eqln_uq9at4:nCZNos5-dwY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Eqln_uq9at4:nCZNos5-dwY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Eqln_uq9at4:nCZNos5-dwY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/Eqln_uq9at4" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>使用RubyParser检查Ruby代码的variable scope</title>
   <link href="http://www.huangzhimin.com/2010/06/26/check-the-ruby-code-using-the-rubyparser-variable-scope/" />
   <updated>2010-06-26T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/06/26/check-the-ruby-code-using-the-rubyparser-variable-scope</id>
   <content type="html">&lt;p&gt;今天参加rubyconfchina，再次聆听ihower的演讲，再次收益匪浅。&lt;/p&gt;

&lt;p&gt;中间在听到Variable Scope突然想到可以使用RubyParser来检查，于是写了几行代码测试，果然是可行的。&lt;/p&gt;

&lt;p&gt;ihower提到在ruby代码中只有在module，class和def才会创建Varible Scope，比如：&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;其中三个var都在不同的scope。这个在RubyParser的解析结果里面有体现出来。比如，ihower提到def会创建一个scope而define_method不会。我们可以用下面的代码来做个实验&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;它的解析结果为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;可以看到class有创建一个scope，defn也有创建一个scope，而define_method却没有。同样地，你也可以通过实验看到class_eval和instance_eval都没有创建scope。完全和ihower讲的一样。&lt;/p&gt;

&lt;p&gt;以后要是什么时候碰到Variable Scope的问题，就可以使用RubyParser来检查啦，实践见真知。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FbQa9SguASKAopOimR2Ay4JcGSs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FbQa9SguASKAopOimR2Ay4JcGSs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FbQa9SguASKAopOimR2Ay4JcGSs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FbQa9SguASKAopOimR2Ay4JcGSs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=m2ZytxF0Iuo:z4wmjRw2x_c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=m2ZytxF0Iuo:z4wmjRw2x_c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=m2ZytxF0Iuo:z4wmjRw2x_c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=m2ZytxF0Iuo:z4wmjRw2x_c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=m2ZytxF0Iuo:z4wmjRw2x_c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=m2ZytxF0Iuo:z4wmjRw2x_c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/m2ZytxF0Iuo" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>barcamp归来</title>
   <link href="http://www.huangzhimin.com/2010/06/13/barcamp-return/" />
   <updated>2010-06-13T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/06/13/barcamp-return</id>
   <content type="html">&lt;p&gt;昨天公司参加了barcamp会议，barcamp会议的形式比较特别，分三个房间，任何人都可以做presentation，你可以去听你感兴趣的话题。不过来的人并不都是做技术的，大多是做市场，推销自己想法的比较多。&lt;/p&gt;

&lt;p&gt;第一场我就把自己讲的内容搞定了，后面可以安心听听别人的想法。&lt;/p&gt;

&lt;div style="width:425px" id="__ss_4485236"&gt;&lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/flyerhzm/css-sprite-best-practices" title="Css sprite best practices"&gt;Css sprite best practices&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse4485236" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cssspritebestpractices-100612193951-phpapp01&amp;stripped_title=css-sprite-best-practices&amp;userName=flyerhzm" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse4485236" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cssspritebestpractices-100612193951-phpapp01&amp;stripped_title=css-sprite-best-practices&amp;userName=flyerhzm" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding:5px 0 12px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/flyerhzm"&gt;Richard Huang&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;


&lt;p&gt;有三个演讲印象比较深刻&lt;/p&gt;

&lt;p&gt;一个是一个老外讲关于上海的演讲，主要是他想为上海的发展做共享，从环境、教育、交通和医疗等方面介绍了上海的问题，希望搭建一个平台来为上海的发展献计献策。惭愧啊，我们平时只会指责政府如何如何。&lt;/p&gt;

&lt;p&gt;另一个是一个MM普及网络流行语，比如悲剧啊，打酱油啊，冏啊，她不仅叫那些老外如何说，而且告诉他们这次词的来由，我听下来都收获不少。&lt;/p&gt;

&lt;p&gt;最后一个是一个老外介绍node.js，他演讲的形式很特别，没有选择ppt，而是直接拿node.js做一个服务器，通过浏览器来显示演讲的内容，蛮喜欢的&lt;/p&gt;

&lt;p&gt;听了一天，感觉比上班还辛苦呢。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/iAiXpziNLkPXmLNGgNmPG8AniFA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iAiXpziNLkPXmLNGgNmPG8AniFA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/iAiXpziNLkPXmLNGgNmPG8AniFA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iAiXpziNLkPXmLNGgNmPG8AniFA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=qKItgLgYZB8:5RkVxSP7ZqA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=qKItgLgYZB8:5RkVxSP7ZqA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=qKItgLgYZB8:5RkVxSP7ZqA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=qKItgLgYZB8:5RkVxSP7ZqA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=qKItgLgYZB8:5RkVxSP7ZqA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=qKItgLgYZB8:5RkVxSP7ZqA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/qKItgLgYZB8" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>nginx上传进度条</title>
   <link href="http://www.huangzhimin.com/2010/06/05/nginx-upload-progress-bar/" />
   <updated>2010-06-05T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/06/05/nginx-upload-progress-bar</id>
   <content type="html">&lt;p&gt;项目中经常需要应用的功能之一就是文件上传，一般对于小文件来说不需要特别的处理，但是一旦碰到允许大尺寸文件上传的时候，用户常常会被长时间的没有变化的上传过程而迷惑，这种时候就需要一个上传进度条来提醒用户。比如我最近一个项目允许用户上传100M的视频文件，上传的过程往往需要持续10多分钟，这种情况如果没有进度条的话，用户可能会以为系统出问题了。项目部署的环境为nginx+lighttpd，上传的过程是这样的：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;用户选择上传的视频，点击提交按钮&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;nginx将视频文件的二进制数据保存为/tmp目录下面的某个文件&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;lighttpd执行rails的代码对/tmp目录下面的上传文件进行处理&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;由此可见，上传视频的过程都是由nginx进行处理的，lighttpd并不知情，它只能通过上传表单了解到上传到/tmp目录下的文件名，这样的好处是，费时的上传过程并不会消耗rails进程。所以我们在做上传进度条的时候就要在nginx身上下功夫了。&lt;/p&gt;

&lt;p&gt;google了一下，发现网上已经有了解决方案，&lt;a href="http://github.com/drogus/jquery-upload-progress"&gt;http://github.com/drogus/jquery-upload-progress&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;同时修改nginx配置文件 ，增加以下这段：&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l nginx -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;应用jquery-upload-progress就是采用ajax轮询，请求/_upload_progress，返回一个json，告诉你上传是否开始，上传了多少字节，总共有多少字节，你只需要比较上传多少字节和总共多少字节就可以得到上传数据的进度，至于进度条的显示只需要些点css就可以搞定了。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/rL3bK0sMWAiw8lMkyXXeFduFHBo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rL3bK0sMWAiw8lMkyXXeFduFHBo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/rL3bK0sMWAiw8lMkyXXeFduFHBo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rL3bK0sMWAiw8lMkyXXeFduFHBo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=SzLKcGGf-YU:JpJOJVUq6KU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=SzLKcGGf-YU:JpJOJVUq6KU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=SzLKcGGf-YU:JpJOJVUq6KU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=SzLKcGGf-YU:JpJOJVUq6KU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=SzLKcGGf-YU:JpJOJVUq6KU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=SzLKcGGf-YU:JpJOJVUq6KU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/SzLKcGGf-YU" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>方便地浏览github上所有的issues</title>
   <link href="http://www.huangzhimin.com/2010/06/02/easy-to-browse-all-the-issues-on-github/" />
   <updated>2010-06-02T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/06/02/easy-to-browse-all-the-issues-on-github</id>
   <content type="html">&lt;p&gt;我在github上面有好几个repositories，经常会有人来报告报告issue，但问题是有时候手头正好有其它的事情需要处理，就没有办法马上修复issue，随着时间的推移，越来越多的issues被积压下来，而且是分散在各个repositories，这让我找起来很费力，必须首先进入repository页面，再点击issues，才能看到相应的issues。我想要是有个页面能够列出所有repositories的issues该多好啊，不过github上面好像没有找到这样的页面。没办法，只好自己动手丰衣足食。&lt;/p&gt;

&lt;p&gt;github提供了&lt;a href="http://develop.github.com/"&gt;api&lt;/a&gt;，这大大方便了开发，同时有相应的ruby实现&lt;a href="http://github.com/fcoury/octopi/"&gt;octopi&lt;/a&gt;。剩下的工作就很简单了，创建一个sinatra项目，接受用户输入的github用户名，通过用户名获取到该github user，再通过user拿到repositories，通过repository拿到issues，最后通过issue拿到comments，所有的数据都轻而易举地获得了，接下来就是稍微美工一下，然后就发布到heroku上面。半天时间搞定，ruby开发就是个快啊。&lt;/p&gt;

&lt;p&gt;heroku上面的地址是：&lt;a href="http://github-issues.heroku.com/"&gt;http://github-issues.heroku.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/a6vy-FUhFPsTdMHwr5FsKeCpUDs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a6vy-FUhFPsTdMHwr5FsKeCpUDs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/a6vy-FUhFPsTdMHwr5FsKeCpUDs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a6vy-FUhFPsTdMHwr5FsKeCpUDs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=0BJ_5gjyYps:tbTTzw-8fRs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=0BJ_5gjyYps:tbTTzw-8fRs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=0BJ_5gjyYps:tbTTzw-8fRs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=0BJ_5gjyYps:tbTTzw-8fRs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=0BJ_5gjyYps:tbTTzw-8fRs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=0BJ_5gjyYps:tbTTzw-8fRs:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/0BJ_5gjyYps" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>追踪图片在外部系统的查看次数</title>
   <link href="http://www.huangzhimin.com/2010/05/20/tracking-image-views-in-the-external-system/" />
   <updated>2010-05-20T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/05/20/tracking-image-views-in-the-external-system</id>
   <content type="html">&lt;p&gt;随着sns网站和web api的兴起，与第三方网站的交互越来越多。比如我们可以向用户facebook好友上的wall推送数据等等来做网站的推广，这就引来一个问题，我们不能只傻乎乎地做推广，更重要的是统计推广的效果。你总共推送了多少数据，有多少人看到了这些数据，又有多少人点击来到了你的网站？这些数据都是可以用来帮助你改进和提高推广的效果。&lt;/p&gt;

&lt;p&gt;对于推送了多少数据和有多少人看到了这些数据，这两者比较容易做到，前者可以在推送数据的时候做记录，后者可以在用户点击进入网站的时候做记录。对于有多少人看到了这些数据就比较麻烦了。&lt;/p&gt;

&lt;p&gt;下面拿facebook为例介绍如何统计数据在外部系统的查看次数。如果是纯文字的话几乎没法做到，但是如果是推送图片或视频的话，可以通过图片的显示次数来统计数据。&lt;/p&gt;

&lt;p&gt;一般往facebook推送图片或视频等图片的时候，只需要在推送的参数中设置图片或视频的完整url即可。然后facebook在显示图片或视频的时候，会发送请求到服务器上，你只需要捕获这个请求并添加相应的逻辑处理。但是问题是，一般部署的rails应用，除了使用rails server(如thin)，还会放置一个web server(如nginx)来做负载均衡，你的图片或视频的请求会直接被web server处理，根本不经过rails server，这样你的逻辑代码就永远不会被调用到了。&lt;/p&gt;

&lt;p&gt;解决的方法就是把传递给facebook的图片或视频url由静态url改成动态url，比如：http://yourdomain.com/assets/test.png改成http://yourdomain.com/assets/1，然后由assets_controller来返回图片&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;到此为止，你已经可以统计你推送的数据被多少人看到了，不过事情到这里还没有结束，通过rails server来上传图片效率是很低的，你应该将这项任务交给web server。以nginx服务器为例，它提供了X-Accel-Redirect选项，负责静态文件的上传。&lt;/p&gt;

&lt;p&gt;首先，修改nginx的配置文件，将/assets路径加入到X-Accel-Redirect&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这段配置的作用是，如果X-Accel-Redirect指定的路径为/assets/image.png，那么nginx会去寻找/var/www/staging/current/public/assets/image.png文件并上传&lt;/p&gt;

&lt;p&gt;然后要将推送到facebook的图片或视频路径由assets/1改为facebook_assets/1，避免和X-Accel-Redirect冲突。&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;可以看到，只需要在reponse header中增加X-Accel-Redirect即可，render :nothing = true表示rails server不处理图片的上传。nginx看到response header中有X-Accel-Redirect选项，就到/var/www/staging/current/public目录下面去寻找相应的图片并上传。&lt;/p&gt;

&lt;p&gt;Lighttpd和Apache2则可以通过X-Sendfile选项来完成同样的事情。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fdhAGBZmktp6tK4-Lds-aUg0G-A/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fdhAGBZmktp6tK4-Lds-aUg0G-A/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fdhAGBZmktp6tK4-Lds-aUg0G-A/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fdhAGBZmktp6tK4-Lds-aUg0G-A/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=2LryhFjHN3E:-l0r63g-BCQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=2LryhFjHN3E:-l0r63g-BCQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=2LryhFjHN3E:-l0r63g-BCQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=2LryhFjHN3E:-l0r63g-BCQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=2LryhFjHN3E:-l0r63g-BCQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=2LryhFjHN3E:-l0r63g-BCQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/2LryhFjHN3E" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Ruby1.9的中文问题</title>
   <link href="http://www.huangzhimin.com/2010/05/15/ruby1-9-chinese-problem/" />
   <updated>2010-05-15T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/05/15/ruby1-9-chinese-problem</id>
   <content type="html">&lt;p&gt;今天在ruby 1.9.1的环境下试了一下1.8.7下面写的一段代码，结果报错：syntax error, unexpected $end, expecting '}'，查看了一下代码，如下&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;语法完全没有问题，判断是中文导致的问题，奇怪的是在1.8.7下面运行正常。google了一下，原来只要在文件开头加上coding就可以了&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/jcJAvww1hhCUIqhlwyFdbrWtk5M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jcJAvww1hhCUIqhlwyFdbrWtk5M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/jcJAvww1hhCUIqhlwyFdbrWtk5M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jcJAvww1hhCUIqhlwyFdbrWtk5M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=E35zANpvvSg:e8TfqsPqPGs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=E35zANpvvSg:e8TfqsPqPGs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=E35zANpvvSg:e8TfqsPqPGs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=E35zANpvvSg:e8TfqsPqPGs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=E35zANpvvSg:e8TfqsPqPGs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=E35zANpvvSg:e8TfqsPqPGs:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/E35zANpvvSg" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>为resque写扩展</title>
   <link href="http://www.huangzhimin.com/2010/05/13/write-to-resque-extension/" />
   <updated>2010-05-13T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/05/13/write-to-resque-extension</id>
   <content type="html">&lt;p&gt;resque是基于redis的ruby类库，用于创建后台任务，把这些后台任务放在多个队列中去，之后在处理它们。github就是使用resque来处理它们的后台任务的。&lt;/p&gt;

&lt;p&gt;对于需要长时间处理的任务，比如发送email，发tweet，图片resize等等，都是resque的用武之地。默认resque就是将任务加到redis的队列中去，然后定时取出来去处理，实际项目中我们往往需要对其增加额外的扩展，比如你需要增加日志功能，增加处理次数的限制，这个时候就可以给resque写一个plugin，就像rails的plugin一样。&lt;/p&gt;

&lt;p&gt;resque定义了非常良好的HOOK，使得为其写扩展变得更加容易。&lt;/p&gt;

&lt;p&gt;resque采取的是每隔n秒从队列中获取一个任务，然后fork一个子进程来执行这个任务。resque定义了before_fork, after_fork, before_perform, after_perform, around_perform, on_failure几个hook，执行顺序如下&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;before_fork&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;fork&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;after_fork&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;before_perform&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;around_perform&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;perform&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;around_perfomr&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;after_perform&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;还有就是发生错误的时候，on_failure会被执行。&lt;/p&gt;

&lt;p&gt;再给一个我写的resque-restriction插件的实例&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;before_perform_restriction检查任务在一个时间段执行的次数，如果执行次数超过规定，抛出Resque::Job::DontPerform异常，它将终止该任务继续执行。&lt;/p&gt;

&lt;p&gt;after_perform_restriction则在任务执行之后，将计数器减一。&lt;/p&gt;

&lt;p&gt;可以看出，resque作为一个后台任务的框架，其api设计非常良好，很容易对其进行扩展，应该多学习学习。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/8UyW1KNXZN_Tyj9a93RZpHA5wGY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8UyW1KNXZN_Tyj9a93RZpHA5wGY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/8UyW1KNXZN_Tyj9a93RZpHA5wGY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8UyW1KNXZN_Tyj9a93RZpHA5wGY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=lt55uVlCDBY:mX_lDe4RMjY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=lt55uVlCDBY:mX_lDe4RMjY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=lt55uVlCDBY:mX_lDe4RMjY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=lt55uVlCDBY:mX_lDe4RMjY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=lt55uVlCDBY:mX_lDe4RMjY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=lt55uVlCDBY:mX_lDe4RMjY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/lt55uVlCDBY" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>git for hostmonster</title>
   <link href="http://www.huangzhimin.com/2010/05/02/git-for-hostmonster/" />
   <updated>2010-05-02T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/05/02/git-for-hostmonster</id>
   <content type="html">&lt;p&gt;前段时间对网站做了些更新，于是在本地修改了代码，再git push，谁知却得到bash: git-receive-pack: command not found的error，我的git repository是放在hostmonster服务器上面的，之前都是正常的，于是提交ticket给hostmonster的support，得到的答复是他们升级的openssh，通过git+ssh不会再读取.bashrc或.ssh/environment文件，也就是说通过git+ssh没有办法修改PATH了。&lt;/p&gt;

&lt;p&gt;没办法了，只能手动将命令的路径补全了，对于git pull/git ps来说，只需要在输入命令的时候增加参数，比如&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;不过每次都输入参数实在麻烦，直接写到配置文件.git/config&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;然后就可以像以前一样git pull/git ps了。&lt;/p&gt;

&lt;p&gt;还有一个问题，那就是capistrano。默认capistrano通过git ls-remote获取最新的commit id，通过git clone来获取最新文件，但是这些命令都没有办法设置upload-pack和receive-pack参数，没办法，只能修改默认的方法定义。&lt;/p&gt;

&lt;p&gt;首先是git ls-remote&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;当命令为git ls-remote的时候，额外加入参数upload-pack&lt;/p&gt;

&lt;p&gt;再就是git checkout&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这个我没有找个比较优雅的方式，只能直接覆盖原来的方法定义，并在git clone的命令中加入upload-pack。&lt;/p&gt;

&lt;p&gt;还有就是当capistrano执行远程命令的时候，同样没有合适的environments，比如执行rake db:migrate的时候，所以需要修改默认的rake命令&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这样当执行rake命令执行，首先读取.bashrc，设置合适的environments，然后再执行rake命令。&lt;/p&gt;

&lt;p&gt;到此为止，一切又恢复了正常。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1-g47HzT2tHBAmoh_CWceSId2uE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1-g47HzT2tHBAmoh_CWceSId2uE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1-g47HzT2tHBAmoh_CWceSId2uE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1-g47HzT2tHBAmoh_CWceSId2uE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=YQ4L5TS_Blk:OLX8vN2EzHQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=YQ4L5TS_Blk:OLX8vN2EzHQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=YQ4L5TS_Blk:OLX8vN2EzHQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=YQ4L5TS_Blk:OLX8vN2EzHQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=YQ4L5TS_Blk:OLX8vN2EzHQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=YQ4L5TS_Blk:OLX8vN2EzHQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/YQ4L5TS_Blk" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>为select和input type=file标签添加样式</title>
   <link href="http://www.huangzhimin.com/2010/04/21/to-select-and-input-type-file-tag-to-add-style/" />
   <updated>2010-04-21T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/04/21/to-select-and-input-type-file-tag-to-add-style</id>
   <content type="html">&lt;p&gt;select和input type=file两个都是html标签，但是它们在不同的浏览器上显示是完全不同，对于那些对UI要求非常高的网站来说，这是不可接受的。由于这两个标签的样式是由浏览器实现的，所以要想完全通过css来统一样式几乎是不可能的，所以我们这里需要借助javascript的帮助。&lt;/p&gt;

&lt;p&gt;看上去这个应该由两个标签组成，左边是一个text field，右边是一个上传的按钮，要想在所有的浏览器上都把input type=file做成这个样子好像没这个可能，可以想到的办法就是设置两个层，下面的层由一个text field和一个按钮组成，上面是一个透明的input type=file的层，高度和宽度正好覆盖下面的层就可以了。&lt;/p&gt;

&lt;p&gt;我是借助 javascript来生成下面的那个层&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l javascript -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这里fakefile就是下面的那个层，&lt;code&gt;&amp;lt;div  class="browser_button"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;是通过css_sprite得到的按钮图片（最近使用 css_sprite到了偏执的状态）。然后就是通过css来区分上下两个层&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;input  type=file的z-index为2，.fakefile的z-index为1，表示fakefile为下面的层，input  type=file为上面的层。input type=file的opacity设置为0，表示input  type=file为透明的，通过position: absolute可以将两个层完全重叠。这样做出来的input  type=file就和之前的图片一模一样了。&lt;/p&gt;

&lt;p&gt;对于select标签的样式修改也可以用相同的办法进行处理。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/nVleFTHLz7l5_Mj5Npjlz0wrHQY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/nVleFTHLz7l5_Mj5Npjlz0wrHQY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/nVleFTHLz7l5_Mj5Npjlz0wrHQY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/nVleFTHLz7l5_Mj5Npjlz0wrHQY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=iafh9FQea2c:TcbQofzRMlo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=iafh9FQea2c:TcbQofzRMlo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=iafh9FQea2c:TcbQofzRMlo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=iafh9FQea2c:TcbQofzRMlo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=iafh9FQea2c:TcbQofzRMlo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=iafh9FQea2c:TcbQofzRMlo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/iafh9FQea2c" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>浙大校友趣味运动会</title>
   <link href="http://www.huangzhimin.com/2010/04/18/zhejiang-university-alumni-fun-games/" />
   <updated>2010-04-18T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/04/18/zhejiang-university-alumni-fun-games</id>
   <content type="html">&lt;p&gt;下午参加了浙大校友趣味运动会，在华师大。&lt;/p&gt;

&lt;p&gt;上半场是组队活动，有跳长绳、拔河和四人五足活动。下半场是羽毛球比赛。我主要是参加了羽毛球比赛，一开始进行25分的淘汰赛，连赢了两盘，不过体力已经成为问题。进入冠军循环赛，才用11分3局2胜，真是累得一塌糊涂，第一个对手非常擅长打高吊球，基本被压在后场，僵持几个回合就比较累了，一急就想劈杀，虽然有几个扣死了，不过大多都是被救回，或者下网，输得比较郁闷，没什么办法。第二个对手旗鼓相当吧，不过还是输了，反应和移动都下降不少，体力成了制约发挥的最大障碍。&lt;/p&gt;

&lt;p&gt;回来的路上洗了个澡，已经感觉右边大腿比较酸，右手胳膊也有点太不起来了，估计明天得单手敲代码了。&lt;/p&gt;

&lt;p&gt;听说浙大校友每周都会在华师大打球的，以后可以经常去玩玩。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/w4x_6o_j-bFeM983u9-P0qTwqXA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/w4x_6o_j-bFeM983u9-P0qTwqXA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/w4x_6o_j-bFeM983u9-P0qTwqXA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/w4x_6o_j-bFeM983u9-P0qTwqXA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=e8Bw1X3Kjew:fIcO_kpK2FE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=e8Bw1X3Kjew:fIcO_kpK2FE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=e8Bw1X3Kjew:fIcO_kpK2FE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=e8Bw1X3Kjew:fIcO_kpK2FE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=e8Bw1X3Kjew:fIcO_kpK2FE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=e8Bw1X3Kjew:fIcO_kpK2FE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/e8Bw1X3Kjew" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>css sprite best practices</title>
   <link href="http://www.huangzhimin.com/2010/04/03/css-sprite-best-practices-english-version/" />
   <updated>2010-04-03T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/04/03/css-sprite-best-practices-english-version</id>
   <content type="html">&lt;p&gt;&lt;a href="/2010/04/02/css-sprite-best-practices-chinese-version"&gt;css sprite最佳实践（中文版）&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Updated on 2010-4-4, thank &lt;a href="http://scottballantyne.com/"&gt;Scott Ballantyne&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;The advantage of using the css sprite is to reduce a large number of http requests, so it makes the web page loaded much faster. I often find it it painful for me to compose a lot of images into one css sprite image and measure the x and y positions for each image.&lt;/p&gt;

&lt;p&gt;Last year, I wrote a &lt;a href="http://github.com/flyerhzm/css_sprite"&gt;css_sprite&lt;/a&gt;  gem, but to use it you need to define all the images you want to do the css sprite in the configuration file, and it is not easy to use. Because of this, recently I rewrote the css_sprite gem, it is not necessary to use configuration file any more by default, the new css_sprite gem follows the idea of Convention Over Configuration. Now the css_sprite gem can do the css sprite automatically.&lt;/p&gt;

&lt;p&gt;First, let's look at the convention of the directory structrue.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://lh6.ggpht.com/_qSmJ0dW70FE/TGdIAsGI6_I/AAAAAAAAATo/3Xhs9JzvDAQ/css_sprite_preview.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;The blue parts on the above image are the css_sprite directories according to convention. That means the directory whose name is css_sprite or css_sprite suffixed (e.g. another_css_sprite) needs to do the css sprite.&lt;/p&gt;

&lt;p&gt;The green parts are images that need to be tranformed into the css sprite. Once you add images to the css_sprite directory or remove images, the css sprite operation will be automatically executed.&lt;/p&gt;

&lt;p&gt;The red parts are automatically generated files. For each css_sprite directory, there is a css sprite image generated, combined by all the images under the css_sprite directory, and there is also a css or sass file generated according to the css_sprite image.&lt;/p&gt;

&lt;p&gt;What about the generated css file?&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;That means, the generated css file follows the naming convention: &lt;em&gt;one image under the css_sprite directory corresponds to one class in the generated css file, the name of class is just the same as the name of image.&lt;/em&gt; The advantage of this is that developers only need to know what images are under css_sprite directory, then they can use the corresponding class names to display these images on the html page.&lt;/p&gt;

&lt;p&gt;One difficulty that you may encounter is adding styles to a class that is being used by css sprite. Below is a description of how you might handle such an issue.&lt;/p&gt;

&lt;p&gt;1. some related classes have some common styles. e.g. to buttons, you may apply them on input or a elements, in common you need to hide the text on input and a elements, hide the border and so on. So you should generate the common styles for these related classes. For example&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;These styles should be added to the automatically generated css file accroding to user's customization. What customizations I always use are icon, logo, button and bg (abbr. for background).&lt;/p&gt;

&lt;p&gt;2. the style for some specified class, e.g. define margin or float for login_button&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;These styles should be written in the user-defined css file, not the automatically generated css file.&lt;/p&gt;

&lt;p&gt;Follow these rules, what you need to do is to put a new image into the css_sprite directory, then use the corresponding class name to display the image on html page. Generating css sprite image and css files are done automatically. Of course when I remove an image from the css_sprite directory, it is also removed from css_sprite image and css.&lt;/p&gt;

&lt;p&gt;These are css sprite best practice I follow. Now it's time to see how to implement these in a rails application.&lt;/p&gt;

&lt;p&gt;1. Install my css_sprite gem/plugin&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;Or&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;Notice, css_sprite gem depends on the rmagick gem, so please make sure RMagick is successfully installed on your system.&lt;/p&gt;

&lt;p&gt;Then add css_sprite gem in the environment.rb or Gemfile&lt;/p&gt;

&lt;p&gt;2. Next make a directory whose name is css_sprite or ends with css_sprite (e.g. another_css_sprite) under public/images directory&lt;/p&gt;

&lt;p&gt;3. If you install the css_sprite as a gem, you should add css_sprite task in Rakefile&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;If you install it as a plugin, you can skip this step&lt;/p&gt;

&lt;p&gt;4. Let's start the css sprite automation&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;5. Put the images which need to do the css sprite under the css_sprite directory, then you will see the automatically generated css sprite image and css files. Now you can use the corresponding class name to display image on html. And don't forget include the stylesheet&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l rhtml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;Do you feel the you are saved from the dull css sprite job? Here are some additional tasks.&lt;/p&gt;

&lt;p&gt;If you want to stop the css sprite automation, run&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;If you want to restart the css sprite automation, run&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;If you only want to run the css_sprite manually instead of automation, run&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;These are the default processes without configuration. If you want to use sass or you want to define common styles for some related classes, you need to define config/css_sprite.yml file&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l yaml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;The effect of the above configuration file is to generate some common styles for all the images whose filename is button suffixed.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l yaml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;The effect of the above configuration file is to generate a sass file, and generate some common styles for all the images whose filename is button suffixed. Please check the difference of the two configuration files, the content followed button: are copied to the automatically generated css or sass file. So please input the content according to the syntax of css or sass.&lt;/p&gt;

&lt;p&gt;Notice, once you changed the configuration file, please make sure stop and start the css_sprite to take effects.&lt;/p&gt;

&lt;p&gt;Finally, let's look at the automatically generated css file.&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;Don't hesitate to use the css_sprite to speed up your productivity, &lt;a href="http://github.com/flyerhzm/css_sprite"&gt;http://github.com/flyerhzm/css_sprite&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/XcSIVZ4i-9evcY9toH8J_Zwofc0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XcSIVZ4i-9evcY9toH8J_Zwofc0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/XcSIVZ4i-9evcY9toH8J_Zwofc0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XcSIVZ4i-9evcY9toH8J_Zwofc0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Vxam_iZS-q8:2pVPNeqtdus:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Vxam_iZS-q8:2pVPNeqtdus:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Vxam_iZS-q8:2pVPNeqtdus:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Vxam_iZS-q8:2pVPNeqtdus:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Vxam_iZS-q8:2pVPNeqtdus:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Vxam_iZS-q8:2pVPNeqtdus:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/Vxam_iZS-q8" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>css sprite最佳实践</title>
   <link href="http://www.huangzhimin.com/2010/04/02/css-sprite-best-practices-chinese-version/" />
   <updated>2010-04-02T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/04/02/css-sprite-best-practices-chinese-version</id>
   <content type="html">&lt;p&gt;&lt;a href="/2010/04/03/css-sprite-best-practices-english-version"&gt;css sprite best practices (english version)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;应用css sprite的好处在于可以大量减少http请求数，从而达到更快加载页面的效果。&lt;/p&gt;

&lt;p&gt;但是对于像我这样的懒人，你让我每次都一个一个把图片copy到一个css_sprite图片里，还得量一下这个每个图片对应的x和y坐标，实在是一种折磨。&lt;/p&gt;

&lt;p&gt;去年我就写了一个&lt;a href="http://github.com/flyerhzm/css_sprite"&gt;css_sprite&lt;/a&gt;的插件，但是由于需要在配置文件中定义所有需要组合在一起的图片，用起来还是很麻烦，不够傻瓜化。最近我把css_sprite插件重写了一遍，默认不需要使用配置文件，遵循rails的Convention Over Configuration的思想，可以做到全自动的css sprite操作。&lt;/p&gt;

&lt;p&gt;首先，让我们看看目录结构的Convention是如何定义的&lt;/p&gt;

&lt;p&gt;&lt;img src="http://lh6.ggpht.com/_qSmJ0dW70FE/TGdIAsGI6_I/AAAAAAAAATo/3Xhs9JzvDAQ/css_sprite_preview.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;上图中蓝色部分就是Convention的css sprite目录，也就是在public/images目录下面的css_sprite目录或者以css_sprite结尾的目录（比如another_css_sprite)，需要执行css_sprite操作。&lt;/p&gt;

&lt;p&gt;绿色部分则是需要被css sprite的图片，你可以动态的在css sprite目录下面增加或删除图片，css sprite操作就会被自动触发。&lt;/p&gt;

&lt;p&gt;而红色部分都是自动生成的，每个对应的css sprite目录，都会生成一个css sprite图片（图片内容为该css sprite目录下的所有图片组合），生成一个css sprite的css文件或者sass文件。&lt;/p&gt;

&lt;p&gt;那么生成的css文件是怎么样的呢&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;也就是说，它生成的css文件遵循如下一个命名规范：&lt;em&gt;一个css sprite目录下的图片对应css里的一个class，图片的名字就是class的名字。&lt;/em&gt;这样的好处在于开发人员只需要知道css sprite目录下面有哪些图片，他就可以在html页面上面使用哪些class名字来显示这些图片，而且当css_sprite的算法发生变化的时候也不会对页面显示产生任何影响。&lt;/p&gt;

&lt;p&gt;实际使用当中你可能会碰到这样的问题：你除了要使用这些css_sprite生成的class名来显示图片，还需要为它们定义额外的style，而这个可以分为两部分：&lt;/p&gt;

&lt;p&gt;1. 一些相关的class有许多共同的style，比如对于button来说，你会把它应用到input或这a上面，一般就需要隐藏input或a标签上面的文字，需要去掉边框等等，所以你需要为这些相关的class生成共同的style，比如&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这些style应该根据用户的定制加入到自动生成的css文件中去。&lt;/p&gt;

&lt;p&gt;2. 某个具体class应用的style，比如login_button需要定义margin或float&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这些style应该写在用户自己的css文件中，而不应该加入到自动生成的css文件中去。&lt;/p&gt;

&lt;p&gt;遵循以上的规则，我需要做的事情就是把一个新的图片扔到css_sprite目录下，然后在页面上使用这个图片对应的class name来显示这个图片，其它的事情（生成css sprite图片和css）都应该是自动完成的，当然当我把一个图片从css_sprite目录下面移除的时候，它也会自动从css_sprite图片和css中移除。听起来很不错吧！&lt;/p&gt;

&lt;p&gt;上面就是我定义的css_sprite最佳实践，理论还不错，下面看看在rails项目中是如何使用的？&lt;/p&gt;

&lt;p&gt;1. 当然是安装我的css_sprite的gem/plugin&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;或者&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;注意，css_sprite依赖于rmagick gem，所以先请确保RMagick已经在你的系统中成功安装。&lt;/p&gt;

&lt;p&gt;然后就是在environment.rb文件或者Gemfile文件中增加css_sprite gem&lt;/p&gt;

&lt;p&gt;2. 在public/images目录下面生成css_sprite目录或者以css_sprite结尾的的目录（如：another_css_sprite)&lt;/p&gt;

&lt;p&gt;3. 如果你是通过gem安装的css_sprite，那么需要在Rakefile中引用css_sprite的task&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;如果你是通过plugin安装的，可以跳过这一步&lt;/p&gt;

&lt;p&gt;4. 开始css sprite自动化之旅&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;5. 把需要做css sprite操作的图片都放入css_sprite目录下面，然后你会看到自动生成的css_sprite图片和css文件，现在你就可以在html页面上引用图片对应的class名字来显示图片咯。对了，别忘了引用生成的css文件哦&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l rhtml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;是不是感觉从机械的css_sprite工作中解脱出来了呀。下面再介绍些额外的tasks&lt;/p&gt;

&lt;p&gt;如果你想结束css_sprite自动化之旅，执行&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;如果你想重新开始css_sprite自动化之旅，执行&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;如果你不需要css_sprite自动化执行，而只想手动执行css_sprite操作，执行&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;上面这些流程都是在没有配置的默认情况下完成的，如果你需要使用sass，或者你需要为某些相关的class定义共同的style，只需要定义config/css_sprite.yml配置文件即可&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l yaml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;上面这个配置文件的作用是为所有的文件名以button结尾的图片，生成一段共同的style。&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l yaml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;上面这段配置文件的作用是指定css_sprite自动生成sass文件，同时为所有的文件名以button结尾的图片，生成一段共同的style。注意两段配置文件的不同，button下面的内容都会完整的复制到自动生成的css或sass文件，所以你需要根据css和sass的语法来填入。&lt;/p&gt;

&lt;p&gt;注意：当修改了配置文件，需要stop再start css_sprite才能生效。&lt;/p&gt;

&lt;p&gt;最后，来我们来看一段自动生成的css文件吧&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;还等什么，赶紧来使用css_sprite来加快你的工作效率吧：&lt;a href="http://github.com/flyerhzm/css_sprite"&gt;http://github.com/flyerhzm/css_sprite&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/bO9BOCqvTOe8xOUHeNx1EZ61PoQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/bO9BOCqvTOe8xOUHeNx1EZ61PoQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/bO9BOCqvTOe8xOUHeNx1EZ61PoQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/bO9BOCqvTOe8xOUHeNx1EZ61PoQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=63G7RzWUQ8I:UPQLyaAlpvI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=63G7RzWUQ8I:UPQLyaAlpvI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=63G7RzWUQ8I:UPQLyaAlpvI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=63G7RzWUQ8I:UPQLyaAlpvI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=63G7RzWUQ8I:UPQLyaAlpvI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=63G7RzWUQ8I:UPQLyaAlpvI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/63G7RzWUQ8I" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>类似facebook connect的方式验证twitter oauth</title>
   <link href="http://www.huangzhimin.com/2010/03/31/manner-similar-to-facebook-connect-verification-twitter-oauth/" />
   <updated>2010-03-31T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/03/31/manner-similar-to-facebook-connect-verification-twitter-oauth</id>
   <content type="html">&lt;p&gt;最近一个项目需要实现类似与uservoice一样的widget，也就是把一段javascript放到任何的网站上，然后动态生成一个iframe来显示我们网站的内容。但是碰到一个问题，在这个widget内需要允许用户使用twiiter oauth的方式登录，但是twitter oauth认证之后会使用window.top来redirect你的页面，这样会重置我们的widget，这显然是对用户很不友好的。同时，我发现facebook connect的方式可以很好的应用在我们的widget上面，因为它不会重新刷新页面。于是我想能不能用类似与facebook connet的方式，弹出一个页面来做twitter oauth的身份验证呢？显然，这是可行的。&lt;/p&gt;

&lt;p&gt;其实很简单的，就是弹出一个页面，在那个页面上做twitter oauth的身份认证，在返回的时候记录session，同时关闭弹出的页面，javascript的代码如下&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l javascript -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;twitter oauth的链接需要这样写&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l html -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;controller端的代码见&lt;a href="http://www.huangzhimin.com/entries/171-oauth-for-twitter"&gt;http://www.huangzhimin.com/entries/171-oauth-for-twitter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这段javascript代码的作用是查找所有class为twiiter_oauth的链接，点击这个链接的时候进入oauth action，然后转发到twitter oauth的authorize_url，用户验证通过并返回之后，进入callback action，callback记录用户的session之后，返回一段self.close()的javascript关闭弹出页面，然后再执行twitter oauth链接的onlogin代码，这里的onlogin的跳转到'/tweets'页面。&lt;/p&gt;

&lt;p&gt;用户使用起来就和facebook connect很像，所以我给它起名为twitter connect，并且发布到了github上面，项目地址如下：&lt;a href="http://github.com/flyerhzm/twitter_connect"&gt;http://github.com/flyerhzm/twitter_connect&lt;/a&gt;，用起来很方便的哦。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/bgG1Gk9VuZJjA8DZWRaXAZhlFj4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/bgG1Gk9VuZJjA8DZWRaXAZhlFj4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/bgG1Gk9VuZJjA8DZWRaXAZhlFj4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/bgG1Gk9VuZJjA8DZWRaXAZhlFj4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=mBieWZ6f3XY:B_q9JLsFqcc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=mBieWZ6f3XY:B_q9JLsFqcc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=mBieWZ6f3XY:B_q9JLsFqcc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=mBieWZ6f3XY:B_q9JLsFqcc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=mBieWZ6f3XY:B_q9JLsFqcc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=mBieWZ6f3XY:B_q9JLsFqcc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/mBieWZ6f3XY" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>使用princely生成pdf</title>
   <link href="http://www.huangzhimin.com/2010/03/24/pdf-generated-using-the-princely/" />
   <updated>2010-03-24T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/03/24/pdf-generated-using-the-princely</id>
   <content type="html">&lt;p&gt;Prince是一个将html和xml转换为pdf的程序，最突出的特点是prince能够根据css来格式化转换之后的pdf，这实在是太适合web程序员了。princely是一个基于prince的rails插件，使用起来也非常方便。&lt;/p&gt;

&lt;p&gt;首先，下载&lt;a href="http://www.princexml.com/download/"&gt;prince&lt;/a&gt;并按照文档进行安装。&lt;/p&gt;

&lt;p&gt;其次，安装princely&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;接着就是在rails项目中生成pdf并供用户下载。定义一个名字叫download的action&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;然后就是定义download.pdf.erb文件，它就和平时定义html.erb是一样的，样式由pdf_css.css决定。&lt;/p&gt;

&lt;p&gt;这样，当用户点击一个链接进入这个download action，服务器就会在后台生成pdf，并发送response给用户，用户的浏览器就弹出下载的对话框。很简单吧&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fuS9KTwipx47PkWwudnBjK7PbGU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fuS9KTwipx47PkWwudnBjK7PbGU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fuS9KTwipx47PkWwudnBjK7PbGU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fuS9KTwipx47PkWwudnBjK7PbGU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=7F4vsXVrawk:cBpHA_HQ6RA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=7F4vsXVrawk:cBpHA_HQ6RA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=7F4vsXVrawk:cBpHA_HQ6RA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=7F4vsXVrawk:cBpHA_HQ6RA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=7F4vsXVrawk:cBpHA_HQ6RA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=7F4vsXVrawk:cBpHA_HQ6RA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/7F4vsXVrawk" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>shanghaionrails 3.20 活动</title>
   <link href="http://www.huangzhimin.com/2010/03/23/shanghaionrails-3-20-activities/" />
   <updated>2010-03-23T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/03/23/shanghaionrails-3-20-activities</id>
   <content type="html">&lt;p&gt;上周六参加了shanghaionrails的线下活动，活动地点就在云岭东路上的汇银铭尊，离我家很近，我就骑着自行车过去了。本次活动是由5173.com赞助的，场地非常不错，不禁感叹卖游戏装备的公司就是有钱啊。&lt;/p&gt;

&lt;p&gt;言归正传，这次活动有四场演讲：&lt;/p&gt;

&lt;p&gt;Leon和nouse带来的主题是"JS2应用"。JS2是factual公司编写的一个javascript框架，它提供一种以Ruby的语法来书写javascript代码的方法，实现了继承、mixins、更好的foreach、声明的getter/seeter方法等等。感觉和coffee-script蛮像的。&lt;/p&gt;

&lt;p&gt;Jason带来的主题是“when ERP fell in love with rails”。主要是讲述了通过rails来开发ERP的经验，以及通过rails开发带来的高效率。&lt;/p&gt;

&lt;p&gt;叶丁丁带来的主题是“NoSQL: Re-think about the world”。主要是介绍了很多NoSQL的产品和它们之间的比较。&lt;/p&gt;

&lt;p&gt;最后我带来的主题是“Static Code Analysis for Ruby"。主要是通过rails_best_practices gem来介绍如何对ruby代码进行静态代码分析的。&lt;/p&gt;

&lt;div style="width:425px" id="__ss_3485220"&gt;&lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/flyerhzm/static-code-analysis-for-ruby" title="Static Code Analysis For Ruby"&gt;Static Code Analysis For Ruby&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse3485220" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=staticcodeanalysisforruby-100320055247-phpapp02&amp;stripped_title=static-code-analysis-for-ruby&amp;userName=flyerhzm" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse3485220" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=staticcodeanalysisforruby-100320055247-phpapp02&amp;stripped_title=static-code-analysis-for-ruby&amp;userName=flyerhzm" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding:5px 0 12px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/flyerhzm"&gt;Richard Huang&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;


&lt;p&gt;最终的讨论环节也异常活跃，大家各抒己见。以后有机会一定要多参加这样的活动。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/oyb3MpLgxze9bhqhDvug98HHMdM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oyb3MpLgxze9bhqhDvug98HHMdM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/oyb3MpLgxze9bhqhDvug98HHMdM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oyb3MpLgxze9bhqhDvug98HHMdM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=DIFPyFnnxSw:FLwYWmEfsIo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=DIFPyFnnxSw:FLwYWmEfsIo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=DIFPyFnnxSw:FLwYWmEfsIo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=DIFPyFnnxSw:FLwYWmEfsIo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=DIFPyFnnxSw:FLwYWmEfsIo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=DIFPyFnnxSw:FLwYWmEfsIo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/DIFPyFnnxSw" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>通过paperclip上传视频并转换为flv格式</title>
   <link href="http://www.huangzhimin.com/2010/03/17/upload-videos-and-convert-to-flv-by-paperclip/" />
   <updated>2010-03-17T00:00:00-07:00</updated>
   <id>http://www.huangzhimin.com/2010/03/17/upload-videos-and-convert-to-flv-by-paperclip</id>
   <content type="html">&lt;p&gt;paperclip作为一个非常流行的文件上传的rails插件，最常被应用的就是上传图片，裁剪，格式转换等等，网上的demo也是一大堆，但是介绍视频上传的却很少。其实paperclip的处理模块定义非常清晰，可以很方便的实现视频的格式转换。&lt;/p&gt;

&lt;p&gt;我们的案例是这样的：用户上传任何视频文件，我们都将其转换为flv格式，然后再显示在网页上。&lt;/p&gt;

&lt;p&gt;首先，安装ffmpeg，所有的转换工作都是使用ffmpeg命令来执行的。安装文档网上有很多，这里就不重复了。不过我在mac下面用port安装之后，转换视频的时候总是报Audio encoding failed错误，需要将ffmpeg依赖的lame降版本到3.97_0。另外你需要安装paperclip插件。&lt;/p&gt;

&lt;p&gt;接着，新建/lib/paperclip_processors目录，同时在该目录下新建flash.rb文件&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;注意，一定要放在lib/paperclip_processors目录下面，这样paperclip才能找到这个视频转换的处理器。&lt;/p&gt;

&lt;p&gt;然后，在model中声明使用视频转换处理器，并定义尺寸&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这样，当用户上传一个test.avi文件时，你会在服务器的上传目录下面找到test_original.avi, test_medium.flv和test_large.flv三个文件。&lt;/p&gt;

&lt;p&gt;最后，在播放视频的时候，只需要把视频的url传给相应的flash播放器（player.swf）即可&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;注：paperclip升级到2.3.3之后，command参数的写法需要修改为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/24S8zvlzP2E85Wv1QJHfA_YH8vk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/24S8zvlzP2E85Wv1QJHfA_YH8vk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/24S8zvlzP2E85Wv1QJHfA_YH8vk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/24S8zvlzP2E85Wv1QJHfA_YH8vk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=g-YtM7ClZd4:NEVVelG0LKc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=g-YtM7ClZd4:NEVVelG0LKc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=g-YtM7ClZd4:NEVVelG0LKc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=g-YtM7ClZd4:NEVVelG0LKc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=g-YtM7ClZd4:NEVVelG0LKc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=g-YtM7ClZd4:NEVVelG0LKc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/g-YtM7ClZd4" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>rails and facebook connect</title>
   <link href="http://www.huangzhimin.com/2010/03/05/rails-and-facebook-connect/" />
   <updated>2010-03-05T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/03/05/rails-and-facebook-connect</id>
   <content type="html">&lt;p&gt;最近项目需要做一些facebook应用，比如要允许用户登录facebook，要获取用户facebook的好友信息等等。登录facebook自然选用时下流行的facebook connect。代码写起来非常简单，用户的体验也非常好。&lt;/p&gt;

&lt;p&gt;首先，进入facebook的开发者页面http://developers.facebook.com/，点击Start building for your site，开始创建你的facebook应用，按照提示一步一步继续。需要注意的是，你可能需要创建两个应用，一个针对本地development环境，一个针对production环境。&lt;/p&gt;

&lt;p&gt;接着，安装facebooker的gem，并且加入到rails gem依赖。在config目录下创建facebooker.yml文件，内容为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l yaml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;在application_controller文件中增加如下代码&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;facebook_session即为用户登录facebook之后所获取的session，通过它可以获取facebook用户相关的所有信息。&lt;/p&gt;

&lt;p&gt;然后就是在html header中引入facebook所需的javascript&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l rhtml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;最后就是在页面上显示facebook登录的图片和文字&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l rhtml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;你也可以只显示facebook的icon，并且在用户登录之后刷新页面&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l rhtml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;用户登录facebook之后，你就可以获取到用户和其好友的信息，比如&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l rhtml -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;详细的接口可以看看facebooker的rdoc。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/MNzGv6FXgMFrbLeQmryCVbjv7Vg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MNzGv6FXgMFrbLeQmryCVbjv7Vg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/MNzGv6FXgMFrbLeQmryCVbjv7Vg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MNzGv6FXgMFrbLeQmryCVbjv7Vg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=5olEO6Mxegg:a018CZNPOOM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=5olEO6Mxegg:a018CZNPOOM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=5olEO6Mxegg:a018CZNPOOM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=5olEO6Mxegg:a018CZNPOOM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=5olEO6Mxegg:a018CZNPOOM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=5olEO6Mxegg:a018CZNPOOM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/5olEO6Mxegg" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>button_to的使用</title>
   <link href="http://www.huangzhimin.com/2010/03/02/button_to-use/" />
   <updated>2010-03-02T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/03/02/button_to-use</id>
   <content type="html">&lt;p&gt;页面间的跳转或者请求，用得最多的就是link_to和form_for，一个发送get或delete请求，一个post或put请求。但是碰到投票之类的链接，虽然是一个post请求，但是form里面却不需要任何数据，碰到这样的情况，我们希望像link_to那样一行搞定。&lt;/p&gt;

&lt;p&gt;也许你会通过link_to 'xx', 'xx', :method =&gt; :delete联想到link_to 'xx', 'xx', :method =&gt; :post，但是很不幸，没有这样使用的。还好，rails提供了一个简单的helperbutton_to&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;生成的html代码如下&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l html -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;另外说一下页面的显示吧，我们使用vote_icon的class，定义一个background image，问题出来了，使用input会出现一个边框，鼠标放上去是箭头，另外vote icon上面还会显示出字来，解决的方法就是&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;嗯，现在就和link image完全一样了。别急，打开IE7和IE6看看，vote icon上面仍然显示出字来，原来IE7和IE6不支持input上面的text-indent，所以要额外加上&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;现在一切就都OK咯！&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/k4wCb4BUJw8o9-exbgksmlOjXco/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/k4wCb4BUJw8o9-exbgksmlOjXco/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/k4wCb4BUJw8o9-exbgksmlOjXco/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/k4wCb4BUJw8o9-exbgksmlOjXco/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Bt37d_MsP1I:MMv2XWkGDcQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Bt37d_MsP1I:MMv2XWkGDcQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Bt37d_MsP1I:MMv2XWkGDcQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Bt37d_MsP1I:MMv2XWkGDcQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=Bt37d_MsP1I:MMv2XWkGDcQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=Bt37d_MsP1I:MMv2XWkGDcQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/Bt37d_MsP1I" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>2009年总结</title>
   <link href="http://www.huangzhimin.com/2010/02/27/2009-summary/" />
   <updated>2010-02-27T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/02/27/2009-summary</id>
   <content type="html">&lt;p&gt;现在才想起来写2009年的总结好像有点晚哦，不过有总比没有好啊。&lt;/p&gt;

&lt;p&gt;2009年可以说是先抑后仰的一年，年初在欧酷的工作不是很开心，发觉自己并不是很适合那种不以技术为核心的创业，自己的价值无法得到体现，同时又没有被认同的感觉，所以打算换个工作。&lt;/p&gt;

&lt;p&gt;3月份拿到ekohe的offer，完全的技术活，工作以Ruby和Rails为主，是自己的兴趣所在，再加上不加班和免费的午餐，让我坚定了选择ekohe的工作。开始工作没多久就接触了很多新的技术，git, postgres等等。同时知道了github这个网站，3月份给rack做了第一个patch，4月份做了 第一个rails plugin。&lt;/p&gt;

&lt;p&gt;4月份在hostmonster买个共享主机，架设自己的博客以及其它的网站。&lt;/p&gt;

&lt;p&gt;5月份在上海举行了RubyConf，我做了Desgn Pattern──from Java to Ruby的主题演讲。第一次给这么多人做主题演讲，不免有些紧张，不过能够与这么多Ruby开发者一起交流，感觉还是很不错的。这一次会议对我的自信心有了很大的提高。&lt;/p&gt;

&lt;p&gt;之后开始不断为rails写plugin，最成功的就算是bullet plugin了，不仅登上了railslab的视频，也被rails的官方blog所推荐。一种极大的认同感让我积极地投身于社区的开发。&lt;/p&gt;

&lt;p&gt;6月份买了几次彩票，不过基本是投入大于产出，所以就放弃了。&lt;/p&gt;

&lt;p&gt;7月份题集网上线，不过需要审核，让我消耗了不少时间。&lt;/p&gt;

&lt;p&gt;8月份参加了Nike的10公里长跑，70分钟完成，比去年有所退步，应该是工作之后晚上跑步的次数减少的缘故吧。然后养个两只小仓鼠，蛮好玩的，可惜一只已经夭折，不过另一只却是胖一塌糊涂。&lt;/p&gt;

&lt;p&gt;10月份参加了Kungfu RailsConf，做了Contributing to Rails by Plugins and Gems主题演讲，同时对于ihower的Rails Best Practices的演讲感同身受，会后把他ppt中的规则做成了一个ruby的静态代码分析工具rails_best_practices，反映也相当不错。&lt;/p&gt;

&lt;p&gt;之后两个月好像都比较平静，没什么波澜呢。&lt;/p&gt;

&lt;p&gt;2009年看电影的次数差不多是之前10多年的总和，女朋友也被我带动这晚上去跑步锻炼，呵呵。就写这么点吧&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/uMmG70eaWdf4awJZyZtpfj2U2sc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uMmG70eaWdf4awJZyZtpfj2U2sc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/uMmG70eaWdf4awJZyZtpfj2U2sc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uMmG70eaWdf4awJZyZtpfj2U2sc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=7DXnpa0ghNQ:Oi3_FMRUu0U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=7DXnpa0ghNQ:Oi3_FMRUu0U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=7DXnpa0ghNQ:Oi3_FMRUu0U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=7DXnpa0ghNQ:Oi3_FMRUu0U:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=7DXnpa0ghNQ:Oi3_FMRUu0U:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=7DXnpa0ghNQ:Oi3_FMRUu0U:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/7DXnpa0ghNQ" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>hover and png for ie6</title>
   <link href="http://www.huangzhimin.com/2010/02/24/hover-and-png-for-ie6/" />
   <updated>2010-02-24T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/02/24/hover-and-png-for-ie6</id>
   <content type="html">&lt;p&gt;IE6可以说是前端设计师们的最大梦魇，不支持圆角，margin double等等问题，使得书写css的时候不得不专门针对IE6浏览器增加额外的规则。&lt;/p&gt;

&lt;p&gt;hover和png透明也是IE6所不支持的，解决方法如下：&lt;/p&gt;

&lt;p&gt;hover可以通过&lt;a href="http://www.xs4all.nl/~peterned/csshover.html"&gt;Whatever:hover&lt;/a&gt;脚本来hack，使用方法很简单，在ie6.css文件中定义&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;png透明需要&lt;a href="http://www.twinhelix.com/css/iepngfix/"&gt;iepngfix&lt;/a&gt;脚本来hack，使用方法稍微复杂些，首先在ie6.css文件中定义&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l css -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;接着在html文件中引入iepngfix_tilebg.js&lt;/p&gt;

&lt;p&gt;然后修改iepngfix.htc文件，修改其中的blank.gif文件路径&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l javascript -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;好了，你的网站现在能够使IE6支持hover和png透明了，不过当png文件是在hover之后才出现的，png透明似乎就不起作用了。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/KzjN4_AZTOjahU0BXSjyxZ9kz8w/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KzjN4_AZTOjahU0BXSjyxZ9kz8w/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/KzjN4_AZTOjahU0BXSjyxZ9kz8w/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KzjN4_AZTOjahU0BXSjyxZ9kz8w/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=fyDCvBxo9nU:EHz16kTMRnY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=fyDCvBxo9nU:EHz16kTMRnY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=fyDCvBxo9nU:EHz16kTMRnY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=fyDCvBxo9nU:EHz16kTMRnY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=fyDCvBxo9nU:EHz16kTMRnY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=fyDCvBxo9nU:EHz16kTMRnY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/fyDCvBxo9nU" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>webrick源码分析——http请求</title>
   <link href="http://www.huangzhimin.com/2010/02/23/webrick-source-code-analysis-http-request/" />
   <updated>2010-02-23T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/02/23/webrick-source-code-analysis-http-request</id>
   <content type="html">&lt;p&gt;http服务器的主要工作就是解析http请求，然后返回http应答。http请求从socket读入，就是一段特定格式的字符串，下面是访问huangzhimn.com首页的http请求&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l text -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;那么webrick是解析这段字符串的呢？之前在分析webrick主要流程的时候讲到，在http服务器从socket读取到数据时，立刻交给WEBrick::HTTPRequest类来解析，解析方法如下&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;第3-8行，读取对方和自己的地址信息（host, port, id）&lt;/p&gt;

&lt;p&gt;第10行，解析http请求的第一行数据，内容为“GET / HTTP/1.1\r\n”，具体解析方法如下&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;读取http请求的第一行，读取之后通过正则匹配获取@request_method为'GET'，@unparsed_url为'/'，@http_version为1.1&lt;/p&gt;

&lt;p&gt;第11-20行，当http版本为1.0或1.1时，对http头部进行处理&lt;/p&gt;

&lt;p&gt;首先，读取http头，读取方法如下：&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;从socket一行一行地读取数据，直到一行为\r\n，并通过HTTPUTils::parse_header方法将字符串数组@raw_header转换为散列@header&lt;/p&gt;

&lt;p&gt;接着，读取cookies，将cookie字符串解析为Cookie对象&lt;/p&gt;

&lt;p&gt;然后是读取accept, accept-charset, accept-encoding, accept-language值，这些值都是多选的，比如Accept: text/html,application/xhtml+xml,application/xml;q=0.9,&lt;em&gt;/&lt;/em&gt;;q=0.8\r\n，所以通过HTTPUtils::parse_qvalues解析出来的结果是一个数组，而且按照q值来排序&lt;/p&gt;

&lt;p&gt;第21行，当request_method为CONNECT时（用于http代理，http1.1协议新增的），不再继续&lt;/p&gt;

&lt;p&gt;第25行，将字符串@unparsed_uri转换成正规的URI实例@parsed_uri&lt;/p&gt;

&lt;p&gt;第26-30行，通过@parsed_uri获取@path, @host, @port和@query_string&lt;/p&gt;

&lt;p&gt;最后，第37-45行，设置keep-alive值。&lt;/p&gt;

&lt;p&gt;WEBrick::HTTPRequest类另外一个重要的方法是body&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;如果http body为空，则返回nil&lt;/p&gt;

&lt;p&gt;http body分为两种，一种是数据一次性全部传入，另一种是一段一段分批传输(chunked)。&lt;/p&gt;

&lt;p&gt;第8-18行就是处理一次性全部传入的数据，根据header中content-length来读取指定长度的数据。&lt;/p&gt;

&lt;p&gt;第3-7行读取chunked分段数据，读取方法为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;chunked分段数据，第一行表明这一段数据的长度，用十六进制表示，第二行开始为需要读取的分段数据。所以读取chunked数据就是读一行chunk_size，读一行chunk data，直到读完为止。&lt;/p&gt;

&lt;p&gt;最后看看WEBrick::HTTPRequest的meta方法，对CGI的理解很有帮助&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/H9z5iK94tPIIttpCmSFhcZ1h61M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/H9z5iK94tPIIttpCmSFhcZ1h61M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/H9z5iK94tPIIttpCmSFhcZ1h61M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/H9z5iK94tPIIttpCmSFhcZ1h61M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=vqtXt9IZ_go:2mpuRUVvA48:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=vqtXt9IZ_go:2mpuRUVvA48:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=vqtXt9IZ_go:2mpuRUVvA48:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=vqtXt9IZ_go:2mpuRUVvA48:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=vqtXt9IZ_go:2mpuRUVvA48:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=vqtXt9IZ_go:2mpuRUVvA48:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/vqtXt9IZ_go" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>paperclip和id_partition</title>
   <link href="http://www.huangzhimin.com/2010/02/02/paperclip-and-id_partition/" />
   <updated>2010-02-02T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/02/02/paperclip-and-id_partition</id>
   <content type="html">&lt;p&gt;很多网站都允许用户上传文件，如何管理这些上传的文件呢？以paperclip为例，其默认文件布局结构为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;每个id都会占据一个目录，问题是文件系统的子目录数量是有限制的，ext3是32k，ext4是64k，所以网站的数据量达到规模时，默认的文件布局并不合适。比较好的方式是采用id_partition，即把id表示成九位，并且分成3级目录，比如：&lt;/p&gt;

&lt;p&gt;1 =&gt; 000/000/001&lt;/p&gt;

&lt;p&gt;10000 =&gt; 000/010/000&lt;/p&gt;

&lt;p&gt;100000000 =&gt; 100/000/000&lt;/p&gt;

&lt;p&gt;这样就无须为文件系统的子目录数量限制担忧了。实现上同样以papaerclip为例，只需要修改其默认的配置参数&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;其中的:id_partition是paperclip内部支持的&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qgr84IB7-Gt7yYTR109SbcMG82s/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qgr84IB7-Gt7yYTR109SbcMG82s/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qgr84IB7-Gt7yYTR109SbcMG82s/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qgr84IB7-Gt7yYTR109SbcMG82s/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=9Qn3NIgDVQk:VGgGmJBGEYc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=9Qn3NIgDVQk:VGgGmJBGEYc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=9Qn3NIgDVQk:VGgGmJBGEYc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=9Qn3NIgDVQk:VGgGmJBGEYc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=9Qn3NIgDVQk:VGgGmJBGEYc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=9Qn3NIgDVQk:VGgGmJBGEYc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/9Qn3NIgDVQk" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>activerecord属性保护</title>
   <link href="http://www.huangzhimin.com/2010/01/30/activerecord-property-protection/" />
   <updated>2010-01-30T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/01/30/activerecord-property-protection</id>
   <content type="html">&lt;p&gt;最近在看rails安全方面的书，第一部分就是关于生成activerecord对象的参数保护问题。平时一直使用，今天心血来潮想起要看看源代码是如何实现的。&lt;/p&gt;

&lt;p&gt;activerecord属性保护就是通过attr_accessible和attr_protected来声明哪些属性可以访问，哪些不可以访问。当然，这些保护只是针对new, create和update_attributes方法，对于直接使用attribute=就无能为力了。&lt;/p&gt;

&lt;p&gt;attr_accessible的源码为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;原来activerecord会生成一个attr_protected属性，来记录所有的需要被保护的字段&lt;/p&gt;

&lt;p&gt;同样attr_accessible会生成attr_accessible属性&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;然后，在传递attributes的时候会调remove_attributes_protected_from_mass_assignment&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;如果没有定义attr_accessible和attr_protected，会防止修改默认的属性（primary_key属性，一般是id和inheritance属性，即type）&lt;/p&gt;

&lt;p&gt;如果没有定义attr_protected，就只允许修改attr_accessible定义的属性，还会防止修改默认的属性&lt;/p&gt;

&lt;p&gt;如果没有定义attr_accessible，就防止修改attr_protected定义的属性，也会防止修改默认的属性&lt;/p&gt;

&lt;p&gt;需要注意的是，如果同时定义attr_protected和attr_accessible的话，就会抛异常&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/P2smxX47K8gdGkYyirJO_L4dfwg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/P2smxX47K8gdGkYyirJO_L4dfwg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/P2smxX47K8gdGkYyirJO_L4dfwg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/P2smxX47K8gdGkYyirJO_L4dfwg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=lX-mbFnaitM:zPXDpw44CqA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=lX-mbFnaitM:zPXDpw44CqA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=lX-mbFnaitM:zPXDpw44CqA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=lX-mbFnaitM:zPXDpw44CqA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=lX-mbFnaitM:zPXDpw44CqA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=lX-mbFnaitM:zPXDpw44CqA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/lX-mbFnaitM" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>webrick源码分析──路由</title>
   <link href="http://www.huangzhimin.com/2010/01/25/webrick-routing-source-code-analysis/" />
   <updated>2010-01-25T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/01/25/webrick-routing-source-code-analysis</id>
   <content type="html">&lt;p&gt;webrick的路由是由WEBrick::HTTPServer::MountTable定义的&lt;/p&gt;

&lt;p&gt;MountTable由@tab和@scanner组成，@tab是一个由script_name到Servlet的Hash，@scanner一个可以匹配所有script_name的正则表达式。其定义如下：&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;MountTable只提供了四个方法：&lt;/p&gt;

&lt;p&gt;[] 根据script_name获取相应的Servlet
[]= 定义scrpt_name与Servlet的对应关系
delete 删除script_name到Servlet的映射
scan 根据request的path返回相应的script_name和path_info&lt;/p&gt;

&lt;p&gt;另外normalize和compile是MountTable的私有方法，normalize会删除url最后的'/'，compile生成可以匹配所有script_name的正则表达式&lt;/p&gt;

&lt;p&gt;看完定义之后，先来看看我们是如何定义路由的&lt;/p&gt;

&lt;p&gt;1. 定义根目录&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;2. 定义任意目录&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;上面定义了两个由FileHandler处理的路由，当path为/'时，在'/home/flyerhzm'目录下查找相应的文件，当path为'/cgi-bin'时，在'/home/flyerhzm/cgi-bin'目录下查找相应的文件，选项:FancyIndexing=true表示，在path对应为某个目录时，显示目录下的所有文件。对应到MountTable的@tab为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;3. 定义Servlet路径&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;当path为'/greet'时，由GreetingServlet来处理，选项options = ['Hi', 'Are you having a nice day?']，其对应到MountTable的@tab为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;4. webrick还可以mount一个proc&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;当path为'/myblock'时，执行这个proc，其对应到MountTable的@tab为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;接下来，让我们看看webrick是如何执行mount操作的&lt;/p&gt;

&lt;p&gt;在httpserver初始化的时候，执行&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;初始化MountTable，同时检查DocumentRoot参数是否设置，如果设置的话，就mount到根目录&lt;/p&gt;

&lt;p&gt;mount, mount_proc和unmount方法定义如下&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;非常简单，只是调用MountTable提供的方法。&lt;/p&gt;

&lt;p&gt;然后来看看webrick是如何根据url来找到相应的servlet。其关键是search_servlet方法&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;参数path就是request的path，经过MountTable#scan解析，分解为script_name和path_info，而通过script_name就能从MountTable中获取servlet类型和选项，WEBrick再根据这个servlet类型和选项，实例化一个servlet，执行用户请求。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ynrWABckxE16x9u9rLqh7sFBNeM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ynrWABckxE16x9u9rLqh7sFBNeM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ynrWABckxE16x9u9rLqh7sFBNeM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ynrWABckxE16x9u9rLqh7sFBNeM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=isC5Ojq--ag:gcey32-8Fyo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=isC5Ojq--ag:gcey32-8Fyo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=isC5Ojq--ag:gcey32-8Fyo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=isC5Ojq--ag:gcey32-8Fyo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=isC5Ojq--ag:gcey32-8Fyo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=isC5Ojq--ag:gcey32-8Fyo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/isC5Ojq--ag" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>困惑</title>
   <link href="http://www.huangzhimin.com/2010/01/17/confused/" />
   <updated>2010-01-17T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/01/17/confused</id>
   <content type="html">&lt;p&gt;昨天发了几个Ticket给Hostmonster，控诉自己的server无法访问中国的网站，得到的结果和预期一样，它们没有限制我访问中国的网站，肯定是被中国给block了，买了dedicated ip就不能更换。&lt;/p&gt;

&lt;p&gt;虽然我还是能够通过google的代理访问，但是终觉不爽。其实我弄个服务器，就是想写点自己的网站，一来练练手，增加点经验；二来呢也指望着赚点零花钱，做得好说不定也是可以创业的基础。相信有不少站长有和我相同的想法。但是现实是网络在中国并不自由。我之所以购买国外的服务器，除了国外的性价比比较高之外，国内的服务器受到GFW的限制，太多的网站无法访问到，再加上动不动就会受到牵连的审查实在不是我这样的懒人能够忍受的。放在国外呢，也提心吊胆，生怕哪天被墙了，就完蛋了。&lt;/p&gt;

&lt;p&gt;最近看到不少抨击中国网络的文章，说实话我并不是很关心政治的人，但是我却是一个希望能够在自由的网络世界谋生的程序员，有时候我在想，要是哪天中国的网络真的被封锁了，网络公司纷纷外逃，我还能拿什么来谋生呢？&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FKrD3uWs6Vrqur539AWOB9vi3Qs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FKrD3uWs6Vrqur539AWOB9vi3Qs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FKrD3uWs6Vrqur539AWOB9vi3Qs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FKrD3uWs6Vrqur539AWOB9vi3Qs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XYzJiuoWWGY:csKtziKzLK8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XYzJiuoWWGY:csKtziKzLK8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=XYzJiuoWWGY:csKtziKzLK8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XYzJiuoWWGY:csKtziKzLK8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=XYzJiuoWWGY:csKtziKzLK8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=XYzJiuoWWGY:csKtziKzLK8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/XYzJiuoWWGY" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>webrick源码分析──主要流程</title>
   <link href="http://www.huangzhimin.com/2010/01/10/webrick-source-of-the-main-flow/" />
   <updated>2010-01-10T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/01/10/webrick-source-of-the-main-flow</id>
   <content type="html">&lt;p&gt;webrick作为ruby自带的一个http server，很适合拿来作为学习之用。首先来看看最简单的使用webrick的示例吧&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这段代码主要是定义了http服务器监听3000端口，根目录在/home/flyerhzm/public_html下，在接收INT或TERM信号时，关闭服务器，然后启动服务器。&lt;/p&gt;

&lt;p&gt;我们分两部分来看，首先看看服务器初始化时做了些什么&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;WEBrick::HTTPServer继承自WEBrick::GenericServer&lt;/p&gt;

&lt;p&gt;WEBrick::GenericServer初始化时&lt;/p&gt;

&lt;p&gt;首先记录所有的配置信息，预定义的WEBrick::Config::HTTP和用户定义的配置信息，包括监听端口，请求超时时间，文档根目录等等。&lt;/p&gt;

&lt;p&gt;接着生成一个定长的队列SizedQueue，用来控制最大的客户端连接数。注意这里的SizedQueue放入的并不是一个线程，而是nil。&lt;/p&gt;

&lt;p&gt;然后打印当前的WEBrick版本号和Ruby版本号。&lt;/p&gt;

&lt;p&gt;最后调用listen方法，生成TCPServer，监听端口。这里可能生成两个TCPServer，一个是IPv4的，一个是IPv6的。&lt;/p&gt;

&lt;p&gt;WEBrick::HTTPServer初始化时主要是定义了http版本号，根据配置信息mount根目录，这里将http://localhost/映射到/home/flyerhzm/public_html/目录，默认DirectoryIndex为[index.html,index.htm,index.cgi,index.rhtml]，即请求为目录时，显示目录下的index.html, index.htm, index.cgi或者index.rhtml，DocumentRootOptions为{ :FancyIndexing = true }，即请求为目录且目录下没有DirectoryIndex定义的文件时，显示目录下的所有文件。这些都是在WEBrick::HTTPServlet::FileHandler中定义的，我会在之后的文章介绍。&lt;/p&gt;

&lt;p&gt;介绍完初始化，下面来看看start方法是如何实现的&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;首先，根据不同的ServerType执行不同的start方法，定义有SimpleServer和Daemon两种，Daemon方式会在以后的文章中介绍，默认为SimpleServer&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;非常简单，就是直接执行传过来的block&lt;/p&gt;

&lt;p&gt;在这个block中生成一个线程组，用来存放处理http请求的线程。&lt;/p&gt;

&lt;p&gt;IO.select(@listeners, nil, nil, 2.0)方法监听@listeners(就是tcp server)，一旦有数据进入就返回，并设置2秒超时，防止进程被挂死。&lt;/p&gt;

&lt;p&gt;对于客户端连接的socket请求，创建一个新的线程来处理，并把这个线程放入线程组中。这里用了一个小技巧来控制线程组中线程的数量。一般我们是将线程插入到SizedQueue来控制线程的数量，而这里SizedQueue插入满nil，每次创建一个线程之前，先从SizedQueue pop一个nil，每次线程处理完在push一个nil，这样，当创建了一定数量的线程时，SizedQueue就为空，无法再pop数据，只有等待一个线程处理完后才能继续。&lt;/p&gt;

&lt;p&gt;接着先来看看如何关闭服务器。webrick提供了两种方法：&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;一是stop，它只是简单地将服务器的状态由Running改为Shutdown，这样就可以从start方法中的循环跳出来，不过由于start方法最后有这么一句话：thgroup.list.each{|th| th.join if th[:WEBrickThread] }，这表示服务器并不会马上关闭，它会等到线程组中所有的线程都执行完毕之后再关闭。&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;二是shutdown，它首先执行stop方法，然后遍历所有的sockets并关闭，这样所有的线程都会买上结束，服务器也会马上停止。&lt;/p&gt;

&lt;p&gt;再来看看每个线程都做了些什么&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;如果传入一个block，就执行这个block，不然就执行run方法，run方法的定义在WEBrick::HTTPServer下&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;run方法中，首先，根据配置信息实例化HTTPResponse和HTTPRequest，在设置的timeout之内读取socket数据，不然停止执行。request对象读取socket数据并根据HTTP协议进行解析（关于http请求和应答的解析将在后文进行介绍），将部分内容（request_method, request_uri等等）赋值给response对象。调用service方法，根据request进行操作，并返回相应的response。最后，通过socket将response发送给客户端。需要注意的是，如果http版本是1.1而且keep_alive为true的话，run方法的循环将一直执行，来保持与客户端的长连接。&lt;/p&gt;

&lt;p&gt;最后看看service方法的代码&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;对于OPTIONS请求是需要特殊处理，返回可以处理的请求（GET, HEAD, POST, OPTIONS），根据请求的path返回相应的servlet，options, script_name和path_info，并获取到servlet实例（一般是用户定义的Servlet类，WEBrick默认有FileHandler, CGIHandler和ProcHandler），然后由具体的servlet实例来处理http请求。&lt;/p&gt;

&lt;p&gt;这就是WEBrick的主要流程，写得比较乱，之后的文章根据WEBrick的功能一部分一部分详细介绍。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/YqiHAziUTZY1XNGK6L1uQQ6snPo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YqiHAziUTZY1XNGK6L1uQQ6snPo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/YqiHAziUTZY1XNGK6L1uQQ6snPo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YqiHAziUTZY1XNGK6L1uQQ6snPo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=HGG5BJPgTYg:WZidomTAk7Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=HGG5BJPgTYg:WZidomTAk7Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=HGG5BJPgTYg:WZidomTAk7Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=HGG5BJPgTYg:WZidomTAk7Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=HGG5BJPgTYg:WZidomTAk7Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=HGG5BJPgTYg:WZidomTAk7Y:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/HGG5BJPgTYg" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>capistrano读取releases目录的错误</title>
   <link href="http://www.huangzhimin.com/2010/01/04/capistrano-error-reading-the-releases-directory/" />
   <updated>2010-01-04T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2010/01/04/capistrano-error-reading-the-releases-directory</id>
   <content type="html">&lt;p&gt;新年刚开始工作就遇到capistrano读取releases目录的错误，deploy之后总是把最新的release目录删除，看来是判断哪个release目录是最新的时候出错了。&lt;/p&gt;

&lt;p&gt;看了下2.5.11源代码，capistrano是这样定义releases目录的&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;其中ls -x的结果是&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;也就是说releases的结果就是&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;再看看删除release部分的代码&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;从这段代码的逻辑可以判断，capistrano会把最新的20100104025008目录删除，显然这不是我们希望看到的结果。&lt;/p&gt;

&lt;p&gt;看了2.5.9的源代码和github上最新的代码，releases却是这样定义的&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;而ls -xt的执行结果是&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;和2.0.11正好相反，看来这就是问题的症结。查了一下lighthouse，https://capistrano.lighthouseapp.com/projects/8716/tickets/88-getting-the-newest-directory#ticket-88-19，原来是因为file cache store才把-t参数去掉了，但是却导致了新的问题，根据上面的解决方案，在config/deploy.rb文件中增加&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;即可&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/LdZWGJNfQruk2aCEsH_qzSxKD9Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LdZWGJNfQruk2aCEsH_qzSxKD9Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/LdZWGJNfQruk2aCEsH_qzSxKD9Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LdZWGJNfQruk2aCEsH_qzSxKD9Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=ISH37LrctkQ:EkLdldYtw7g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=ISH37LrctkQ:EkLdldYtw7g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=ISH37LrctkQ:EkLdldYtw7g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=ISH37LrctkQ:EkLdldYtw7g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=ISH37LrctkQ:EkLdldYtw7g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=ISH37LrctkQ:EkLdldYtw7g:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/ISH37LrctkQ" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Fiber in Ruby 1.9</title>
   <link href="http://www.huangzhimin.com/2009/12/28/fiber-in-ruby-1-9/" />
   <updated>2009-12-28T00:00:00-08:00</updated>
   <id>http://www.huangzhimin.com/2009/12/28/fiber-in-ruby-1-9</id>
   <content type="html">&lt;p&gt;Ruby 1.9新推出了Fiber这个新的概念，有人说它是轻量级的Thread，其实不然。它是一段代码块，可以停止、继续，可以有返回值、写入值，有多个Fiber时，它们的执行顺序是固定。它和Thread相似的是，它的执行不是线性的，它可以在中途停止，将控制权交给主程序或者是其它的Fiber，但是中控制权交接的过程是由你来控制的，而不是线程调度程序。所以有时候Fiber可以完成之前只能用Thread才能完成的任务（比如：Producer-Consumer）。&lt;/p&gt;

&lt;p&gt;先来看看一个例子吧：&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;运行结果是&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;首先，Fiber.new定义了一个Fiber，但是并不会执行，直到调用这个Fiber的resume方法，这个Fiber才会执行，并且当执行到Fiber.yield时停止，并且把yield的参数返回给主程序，同时将控制权将给主程序。然后主程序继续执行，调用这个Fiber的resume方法，这个Fiber从刚才停止的地方继续执行，直到Fiber.yield，以此类推。当这个Fiber执行完毕时，Fiber#alive?返回false，如果这个时候继续调用Fiber#resume，系统将抛出异常。&lt;/p&gt;

&lt;p&gt;运行结果稍微与我们的预想有点偏差，我们并不需要最后一行1..3，原因是在调用三次Fiber#resume分别返回1、2、3，这个时候Fiber并没有执行完毕，所以Fiber#alive?仍然返回true，第四次调用Fiber#resume返回的这个Fiber block内的返回值，这里就是(1..3)，所以我们需要对程序做点小小的修改&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这下运行的结果就和预期一致了。&lt;/p&gt;

&lt;p&gt;再来看看如何向Fiber写入数据&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;运行结果&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;这和从Fiber中读取数据是个相反的操作，通过给Fiber#resume传递参数将数据作为Fiber.yield的返回值传入Fiber。&lt;/p&gt;

&lt;p&gt;你可能会很奇怪，为什么只打印了2和3，没有1呢？因为在第一次调用Fiber#resume的时候，Fiber还没有开始，resume的参数是传递给Fiber block的，当这个Fiber运行到Fiber.yield时，这个Fiber停止，然后第二次调用Fiber#resume的时候，将2传递了Fiber，并作为yield的返回值，所以打印了2，我们需要修改一下代码来打印1、2、3&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l ruby -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;运行结果为&lt;/p&gt;

&lt;p&gt;Liquid error: No such file or directory - pygmentize -l bash -f html -O encoding=utf-8&lt;/p&gt;

&lt;p&gt;如果需要在两个Fiber之间切换的话，可以使用Fiber#transfer，用来实现Producer-Consumer。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/2AdVYNva6SVsEnI1HFp_IbiHVhk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2AdVYNva6SVsEnI1HFp_IbiHVhk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/2AdVYNva6SVsEnI1HFp_IbiHVhk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2AdVYNva6SVsEnI1HFp_IbiHVhk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=g98Oq8OoACU:L-PORle9-fA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=g98Oq8OoACU:L-PORle9-fA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=g98Oq8OoACU:L-PORle9-fA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=g98Oq8OoACU:L-PORle9-fA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?i=g98Oq8OoACU:L-PORle9-fA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/richard-huang?a=g98Oq8OoACU:L-PORle9-fA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/richard-huang?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/richard-huang/~4/g98Oq8OoACU" height="1" width="1"/&gt;</content>
 </entry>
 

</feed>

