<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>zhangyuan (Yuan Cheung)</title>
    <link>https://ruby-china.org/zhangyuan</link>
    <description>I'm not the only one.</description>
    <language>en-us</language>
    <item>
      <title>Rails 是如何做到 development 下修改代码后，不重启服务器就可以重新加载代码？</title>
      <description>&lt;p&gt;在 development 环境下，修改项目代码，不用重启服务器，刷新页面就能看到代码变化。为什么？是用 &lt;code&gt;load&lt;/code&gt; 重新加载了代码吗？——没那么简单。&lt;/p&gt;

&lt;p&gt;下面在 Rails-3.2.13 代码里找到它的实现。&lt;/p&gt;

&lt;p&gt;首先，这和 Rails 加载常量的方式有关。 &lt;code&gt;ActiveSupport::Dependencies::ModuleConstMissing&lt;/code&gt; 模块重写了 &lt;code&gt;Module#const_missing&lt;/code&gt; 方法。当程序遇到未定义的常量时，就会调用到该方法。&lt;code&gt;const_missing&lt;/code&gt; 是类方法，所以应该定义在类的类 &lt;code&gt;Class&lt;/code&gt; 上，而 &lt;code&gt;Module&lt;/code&gt; 是 &lt;code&gt;Class&lt;/code&gt; 的父类。在重写的 &lt;code&gt;const_missing&lt;/code&gt; 方法里，会根据常量名，按照路径的惯例去加载对应的文件，当找到后，就加载文件，并且把常量保存起来（常量保存在 &lt;code&gt;ActiveSupport::Dependencies.autoloaded_constants&lt;/code&gt; ，加载过的文件路径保存在 &lt;code&gt;ActiveSupport::Dependencies.history&lt;/code&gt; ）。当需要时，调用 &lt;code&gt;ActiveSupport::Dependencies.clear&lt;/code&gt; 移除已经加载过的常量（可参考 &lt;a href="http://blog.yuaz.net/archives/415" rel="nofollow" target="_blank"&gt;http://blog.yuaz.net/archives/415&lt;/a&gt; ，很多人认为 Rails 加载类的方式，用到了 &lt;code&gt;autoload&lt;/code&gt; &lt;a href="http://ruby-doc.org/core-1.9.3/Module.html#method-i-autoload" rel="nofollow" target="_blank"&gt;http://ruby-doc.org/core-1.9.3/Module.html#method-i-autoload&lt;/a&gt; ，是不对的）。&lt;/p&gt;

&lt;p&gt;所以，Rails 可以用 &lt;code&gt;ActiveSupport::Dependencies.clear&lt;/code&gt; 在某个时刻清除加载的类和模块的。&lt;/p&gt;

&lt;p&gt;在代码里搜 &lt;code&gt;ActiveSupport::Dependencies.clear&lt;/code&gt; ，找到 &lt;code&gt;railties/lib/rails/application/finisher.rb&lt;/code&gt; 里可以看到，有如下的初始化步骤。这里定义了一个 lambda&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Set app reload just after the finisher hook to ensure&lt;/span&gt;
&lt;span class="c1"&gt;# paths added in the hook are still loaded.&lt;/span&gt;
&lt;span class="n"&gt;initializer&lt;/span&gt; &lt;span class="ss"&gt;:set_clear_dependencies_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:group&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DescendantsTracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;
    &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Dependencies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload_classes_only_on_change&lt;/span&gt;
    &lt;span class="n"&gt;reloader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file_watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;watchable_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reloaders&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;reloader&lt;/span&gt;
    &lt;span class="c1"&gt;# We need to set a to_prepare callback regardless of the reloader result, i.e.&lt;/span&gt;
    &lt;span class="c1"&gt;# models should be reloaded if any of the reloaders (i18n, routes) were updated.&lt;/span&gt;
    &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Reloader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:prepend&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="n"&gt;reloader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Reloader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_cleanup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后将其传给 &lt;code&gt;ActionDispatch::Reloader.to_prepare&lt;/code&gt; 或 &lt;code&gt;ActionDispatch::Reloader.to_cleanup&lt;/code&gt; 。打开其源码 &lt;code&gt;actionpack/lib/action_dispatch/middleware/reloader.rb&lt;/code&gt; 看到 &lt;code&gt;ActionDispatch::Reloader&lt;/code&gt; 是一个 rack middleware，在其 &lt;code&gt;ActionDispatch::Reloader#call&lt;/code&gt; 方法里，会在每次请求前（ &lt;code&gt;ActionDispatch::Reloader#prepare!&lt;/code&gt; ）和请求后（ &lt;code&gt;ActionDispatch::Reloader#cleanup!&lt;/code&gt; ），调用到初始化步骤里的 callback，此时就移除了已经加载过的常量。这样每次请求前或者后，就会移除以及加载的常量；对代码的改动，就会立即生效。&lt;/p&gt;

&lt;p&gt;那么，为什么在 development 环境下，会重新加载代码，在 production 下不会呢？&lt;/p&gt;

&lt;p&gt;搜索 &lt;code&gt;ActionDispatch::Reloader&lt;/code&gt; 关键字，可以在 &lt;code&gt;railties/lib/rails/application.rb&lt;/code&gt; 找到&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cache_classes&lt;/span&gt;
  &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Reloader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload_dependencies?&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在此处看到，有个开关 &lt;code&gt;config.cache_classes&lt;/code&gt; 。在 Rails 生成的环境配置里， &lt;code&gt;config/environments/development.rb&lt;/code&gt;里有 &lt;code&gt;config.cache_classes = false&lt;/code&gt; ，&lt;code&gt;config/environments/production.rb&lt;/code&gt; 里有 &lt;code&gt;config.cache_classes = true&lt;/code&gt; 。所以，只有在 development 环境下才会使用 &lt;code&gt;::ActionDispatch::Reloader&lt;/code&gt;。因此，production 下修改代码，不会生效，必须重启。&lt;/p&gt;

&lt;p&gt;最终的结论就是：在 development 下 Rails 使用了 &lt;code&gt;ActionDispatch::Reloader&lt;/code&gt; 这个 middleware，在每次请求时调用 &lt;code&gt;ActiveSupport::Dependencies.clear&lt;/code&gt; 来移除已经加载的类和模块；这样在程序用到他们时，就会重新加载。&lt;/p&gt;

&lt;p&gt;另外，在 production 环境下，Rails 并不是在用到这些常量时，才去通过 const_missing 的方式加载。而是在初始化的时候，用 eager_load! 的方式，把 &lt;code&gt;Rails.configuration.eager_load_paths&lt;/code&gt; 里的文件都加载（默认是 app 的若干目录，可见 railties/lib/rails/engine/configuration.rb 里的 &lt;code&gt;Rails::Engine::Configuration#paths&lt;/code&gt;，这样也是为了线程安全吧）。 &lt;/p&gt;

&lt;p&gt;来源 &lt;a href="http://blog.yuaz.net/archives/462" rel="nofollow" target="_blank"&gt;http://blog.yuaz.net/archives/462&lt;/a&gt;&lt;/p&gt;</description>
      <author>zhangyuan</author>
      <pubDate>Thu, 24 Oct 2013 00:13:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/14979</link>
      <guid>https://ruby-china.org/topics/14979</guid>
    </item>
    <item>
      <title>在阿里云上使用 https clone github 上的代码报证书错误，有人遇到吗？</title>
      <description>&lt;p&gt;今天要在阿里云服务器上部署一个项目，结果第一步安装 rbenv-installer 就悲剧，报证书错误……尝试了一下在服务器上 clone 项目，用 https 协议时，报错：&lt;/p&gt;

&lt;p&gt;&lt;img src="//l.ruby-china.com/photo/a20095a3ee8dac7ef508bccca426ac74.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;服务器 IP 显示是在上海。而我在本地（成都）可以正常 clone。&lt;/p&gt;

&lt;p&gt;这个敏感的时期，真不知道这是墙的原因，还是阿里云的原因。我只好改用 git 协议、或者加上 &lt;code&gt;env GIT_SSL_NO_VERIFY=true&lt;/code&gt; 来 clone 了。有人遇到过吗？&lt;/p&gt;</description>
      <author>zhangyuan</author>
      <pubDate>Tue, 29 Jan 2013 01:32:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/8447</link>
      <guid>https://ruby-china.org/topics/8447</guid>
    </item>
    <item>
      <title>请问有人遇到在内网开发时，rails 通过反向代理运行在 nginx 后端，调用 request.remote_ip 无法获取客户端 IP 或者报错吗？</title>
      <description>&lt;p&gt;由于开发时，要同时运行多个项目，并且都在 80 端口。所以项目在 3000 端口启动，然后通过 Nginx 做反向代理。客户端请求 nginx 即可。&lt;/p&gt;

&lt;p&gt;但是在 controller 里调用 &lt;code&gt;request.remote_ip&lt;/code&gt; 得到的 IP 是  127.0.0.1，而不是客户端 IP。于是我在 Nginx 里设置了 HTTP_CLIENT_IP 头为客户端 IP 后，就会抛异常 &lt;code&gt;IpSpoofAttackError&lt;/code&gt;，报错：IP spoofing attack。&lt;/p&gt;

&lt;p&gt;这只是在内网出的问题。我使用同样的 Nginx 配置，并在公网里的项目里，调用 &lt;code&gt;request.remote_ip&lt;/code&gt; 能正常返回客户端 IP。&lt;/p&gt;

&lt;p&gt;细节如下：&lt;/p&gt;

&lt;p&gt;Nginx 这样配置的&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
  listen 80;
  server_name abc.com;
    location / { 
    proxy_redirect     off;
    proxy_set_header   Host $host;
    proxy_set_header   X-Forwarded-Host $host;
    proxy_set_header   X-Forwarded-Server $host;

    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_buffering    on; 

    if (!-f $request_filename) {
      proxy_pass http://127.0.0.1:3000;
      break;
    }   
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后来找到这个问题 &lt;a href="http://stackoverflow.com/questions/10710486/wrong-ip-address-with-nginx-unicorn-rails" rel="nofollow" target="_blank"&gt;http://stackoverflow.com/questions/10710486/wrong-ip-address-with-nginx-unicorn-rails&lt;/a&gt; ，添加了一行命令&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;proxy_set_header   CLIENT_IP $remote_addr;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来就报错了。抛出 IpSpoofAttackError 异常，提示 IP spoofing attack?，给打印出了 HTTP_CLIENT_IP 和 HTTP_X_FORWARDED_FOR。对应 rails 源码中的  &lt;a href="https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_dispatch/middleware/remote_ip.rb" rel="nofollow" target="_blank"&gt;https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_dispatch/middleware/remote_ip.rb&lt;/a&gt; 文件。&lt;/p&gt;

&lt;p&gt;读了一下源码，发现是 rails 会根据 HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR 或者 REMOTE_ADDR 来得到 remote_ip。&lt;/p&gt;

&lt;p&gt;第一种情况 Nginx 没有设置 CLIENT_IP 时，rails 拿到的 HTTP_CLIENT_IP 为&lt;code&gt;nil&lt;/code&gt;，就从 HTTP_X_FORWARDED_FOR 里找，但找之前，会处理一下，去掉 HTTP_X_FORWARDED_FOR 里的内网 IP（客户端的 IP 是 192.168.x.x），所以在 HTTP_X_FORWARDED_FOR 里还是找不到。只能在 REMOTE_ADDR 找了。而 REMOTE_ADDR 返回是 127.0.0.1。&lt;/p&gt;

&lt;p&gt;第二种情况 Nginx 设置了 CLIENT_IP，rails 拿到的 HTTP_CLIENT_IP 是 192.168.x.x。而这个 IP，并不在处理后的 HTTP_X_FORWARDED_FOR 里，所以报错了。&lt;/p&gt;

&lt;p&gt;没找到有效的解决办法，我只能在 development.rb 里配置&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_dispatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ip_spoofing_check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为不想在生产环境里关闭这个检查，所以不想在 production.rb 里增加这个配置。但是，在内网用 production.rb 测试时，又会遇到错误。&lt;/p&gt;

&lt;p&gt;请问大家有遇到这个情况吗？该如何解决呢？&lt;/p&gt;</description>
      <author>zhangyuan</author>
      <pubDate>Sat, 26 Jan 2013 00:03:53 +0800</pubDate>
      <link>https://ruby-china.org/topics/8375</link>
      <guid>https://ruby-china.org/topics/8375</guid>
    </item>
    <item>
      <title>通过 GiHub 账户登陆后，穿越到了另一个同学的账户里</title>
      <description>&lt;p&gt;昨晚用别人的电脑，由于忘记密码，就使用了 GitHub 账号登录。我的 ruby-china.org 和 github.com 使用的账户是同一个邮箱。登录后，就进入了另外一个同学的账户里了（我不认识这位同学）。昨天试了多次，都是这样；今天终于用自己的电脑了，登录上来发个图如下。&lt;/p&gt;

&lt;p&gt;&lt;img src="//l.ruby-china.com/photo/6f0c4f427dc4ee9c72c7447f4562a277.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;我看了一下源码，没看明白问题在哪里，难道我的 github 账号绑定在其他用户上了？
PS：发现某些地方“登录”写成了“登陆”⋯⋯  &lt;/p&gt;</description>
      <author>zhangyuan</author>
      <pubDate>Fri, 09 Mar 2012 20:41:39 +0800</pubDate>
      <link>https://ruby-china.org/topics/1757</link>
      <guid>https://ruby-china.org/topics/1757</guid>
    </item>
    <item>
      <title>请教如何设计获取多个资源的 URL (或者 API)</title>
      <description>&lt;p&gt;比如，对于资源 Post，
请求一个资源的的地址为 &lt;a href="http://example.com/posts/1" rel="nofollow" target="_blank"&gt;http://example.com/posts/1&lt;/a&gt;
请求一个命名集合（collection）的资源，比如最新的 posts，可以用 &lt;a href="http://example.com/posts/recent" rel="nofollow" target="_blank"&gt;http://example.com/posts/recent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;如果我想请求多个离散的资源，比如 id=2, id=12, id=13, id=4，可以访问 &lt;a href="http://example.com/posts/:id" rel="nofollow" target="_blank"&gt;http://example.com/posts/:id&lt;/a&gt; 这个接口 4 次，但这样多次请求，效率不高；在实际使用中，结合其他接口，很有可能出现类似于 SQL 中的 1+N 问题。所以希望在一次请求中，返回满足要求的结果。&lt;/p&gt;

&lt;p&gt;SO 上有一个讨论： &lt;a href="http://stackoverflow.com/questions/4541338/how-to-construct-a-rest-api-that-takes-an-array-of-ids-for-the-resources" rel="nofollow" target="_blank" title=""&gt;How to construct a REST API that takes an array of id's for the resources&lt;/a&gt; ，提到可以用类似
&lt;code&gt;
http://example.com/posts/?id=2,12,14,4
&lt;/code&gt;
这种形式的接口。但是根据&lt;a href="http://en.wikipedia.org/wiki/Query_string" rel="nofollow" target="_blank" title=""&gt;Query String&lt;/a&gt;的规范：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Letters (A-Z and a-z), numbers (0-9) and the characters '.','-','~' and '_' are left as-is
SPACE is encoded as '+' or %20[citation needed]
All other characters are encoded as %FF hex representation with any non-ASCII characters first encoded as UTF-8 (or other specified encoding)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;所以 Query String 里的&lt;code&gt;,&lt;/code&gt;应该用&lt;code&gt;%2C&lt;/code&gt;代替，所以上面的 URL 应为&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
http://example.com/posts?id=2%2C12%2C14%2C4
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这样看起来很别扭。有没有其他的解决方案呢？&lt;/p&gt;</description>
      <author>zhangyuan</author>
      <pubDate>Sun, 04 Mar 2012 00:45:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/1592</link>
      <guid>https://ruby-china.org/topics/1592</guid>
    </item>
    <item>
      <title>缓存问题：话题相关页面 可能 半个小时内没有热门节点</title>
      <description>&lt;p&gt;大家好，刚才看了一下网站源码，发现一个关于缓存失效的问题，导致半个小时内没有热门节点。&lt;/p&gt;

&lt;p&gt;不知道说得对不对，如有错误，请见谅哈：&lt;/p&gt;

&lt;p&gt;生成话题边栏时，
&lt;a href="https://github.com/huacnlee/ruby-china/blob/master/app/controllers/topics_controller.rb" rel="nofollow" target="_blank"&gt;https://github.com/huacnlee/ruby-china/blob/master/app/controllers/topics_controller.rb&lt;/a&gt;
判断片段缓存是否存在&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def init_list_sidebar 
 if !fragment_exist? "topic/init_list_sidebar/hot_nodes"
    @hot_nodes = Node.hots.limit(10)
  end
  set_seo_meta("社区")
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在 views 里生成缓存
&lt;a href="https://github.com/huacnlee/ruby-china/blob/master/app/views/topics/_sidebar.html.erb" rel="nofollow" target="_blank"&gt;https://github.com/huacnlee/ruby-china/blob/master/app/views/topics/_sidebar.html.erb&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;%= cache("topic/init_list_sidebar/hot_nodes",:expires_in =&amp;gt; 30.minutes) do %&amp;gt;
  &amp;lt;% if not @hot_nodes.blank? %&amp;gt;
  &amp;lt;div class="hot_nodes nodes box"&amp;gt;
    &amp;lt;h2&amp;gt;热门节点&amp;lt;/h2&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;% @hot_nodes.each do |node| %&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="&amp;lt;%= node_topics_path(:id =&amp;gt; node.id) %&amp;gt;"&amp;gt;&amp;lt;%= node.name %&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;% end %&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在一些临界时刻，可能出现下面问题：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;请求到达 controller 时，如果缓存“topic/init_list_sidebar/hot_nodes”还在，就不会有实例变量 &lt;a href="/hot_nodes" class="user-mention" title="@hot_nodes"&gt;&lt;i&gt;@&lt;/i&gt;hot_nodes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;在渲染视图之前，30 分钟的时间到了，缓存失效&lt;/li&gt;
&lt;li&gt;由于&lt;a href="/hot_nodes" class="user-mention" title="@hot_nodes"&gt;&lt;i&gt;@&lt;/i&gt;hot_nodes&lt;/a&gt; 为 nil，然后半个小时以内，就没有热门节点了&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;一般情况下，在 controller 里查数据库，在视图里渲染。但是和缓存相关时，这样做可能就有问题。  &lt;/p&gt;</description>
      <author>zhangyuan</author>
      <pubDate>Sun, 20 Nov 2011 01:56:22 +0800</pubDate>
      <link>https://ruby-china.org/topics/95</link>
      <guid>https://ruby-china.org/topics/95</guid>
    </item>
  </channel>
</rss>
