<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>dothide (DotHide)</title>
    <link>https://ruby-china.org/dothide</link>
    <description>取是能力，舍是境界，天道酬勤，忠于实践</description>
    <language>en-us</language>
    <item>
      <title>你的 Safari 会出现这个问题么？</title>
      <description>&lt;p&gt;&lt;strong&gt;【谨慎】建议大家保存内容，然后重新打开 Safari 尝试&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;在 Safari 浏览器中输入内容，就比如新开一个帖子，然后编辑吧&lt;/li&gt;
&lt;li&gt;接下来按住 &lt;code&gt;CapsLock&lt;/code&gt;，然后鼠标随便点几下或者键盘上下左右敲几下，3 秒钟后浏览器必死！&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;发现这个问题，是原本想按住 &lt;code&gt;Shift&lt;/code&gt; 选中某行文字的，结果按到 &lt;code&gt;CapsLock&lt;/code&gt; 上去了，按错后发现浏览器死了，然后再试还是死，由此发现！不知是否为操作系统 BUG？是否有人遇到过同样的问题？&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Sat, 10 Dec 2016 11:00:47 +0800</pubDate>
      <link>https://ruby-china.org/topics/31866</link>
      <guid>https://ruby-china.org/topics/31866</guid>
    </item>
    <item>
      <title> Rails 5 中每个订单都有自己的 CSRF Token</title>
      <description>&lt;p&gt;这篇博客是我们 &lt;a href="http://blog.bigbinary.com/categories/Rails-5" rel="nofollow" target="_blank" title=""&gt;《Rails 5 系列文章》&lt;/a&gt; 中的一篇。&lt;/p&gt;

&lt;p&gt;我们曾 &lt;a href="http://blog.bigbinary.com/2012/05/10/csrf-and-rails.html" rel="nofollow" target="_blank" title=""&gt;写过一篇博客&lt;/a&gt; 介绍什么是 CSRF 以及如何在 Rails 4 中避免 CSRF，建议你读一下那篇文章来更好地理解本文。&lt;/p&gt;
&lt;h3 id="嵌套表单可以绕过 Rails 4 提供的 CSRF 保护"&gt;嵌套表单可以绕过 Rails 4 提供的 CSRF 保护&lt;/h3&gt;
&lt;p&gt;一个典型 Rails 4 生成的表单如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"post"&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/money_transfer"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"hidden"&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"authenticity_token"&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"token_value"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;黑客使用 JS 代码注入在 Rails 生成表单标签之上嵌套另一个表单。现在它看起像这样：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post"&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://www.fraud.com/fraud"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"post"&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/money_transfer"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"hidden"&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"authenticity_token"&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"token_value"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;HTML 规范 &lt;a href="http://stackoverflow.com/questions/379610/can-you-nest-html-forms" rel="nofollow" target="_blank" title=""&gt;不允许使用嵌套表单&lt;/a&gt; 。&lt;/p&gt;

&lt;p&gt;由于不允许使用嵌套表单，浏览器将接受最顶层的表单。这样一来就变成了黑客创建的表单。当该表单被提交时，「authenticity_token」也同时被提交，Rails 将做自检然后说一切都正常，这样黑客有可能黑了该网站。&lt;/p&gt;
&lt;h3 id="Rails 5 通过为表单生成自定义令牌来修复该问题"&gt;Rails 5 通过为表单生成自定义令牌来修复该问题&lt;/h3&gt;
&lt;p&gt;在 Rails 5 中，CSRF 能够被加到任意表单中。每个 CSRF token 仅会被其自身所在表单的 method/action 作验证。你可以在控制器中添加以下代码行来增加针对控制器每个表单的 method/action 的真伪令牌。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&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;per_form_csrf_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在每个控制器里添加该行代码会感觉繁琐，因此你也可以初始化以下代码，为应用的所有控制器都启用该行为。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/application.rb&lt;/span&gt;
&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;per_form_csrf_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将增加针对整个应用每个表单的 method/action 的真伪令牌。之后生成的表单将会如下所示：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;method= &lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/money_transfer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"authenticity_token"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"money_transfer_post_action_token"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里包含的真伪令牌将仅针对 &lt;code&gt;money_transfer&lt;/code&gt;动作和 &lt;code&gt;post&lt;/code&gt; 方法。尽管攻击者依然可以在这里拿到 authenticity_token，但攻击将被受限于 &lt;code&gt;money_transfer post&lt;/code&gt; 动作。&lt;/p&gt;

&lt;p&gt;作者 &lt;a href="https://github.com/prajakta-tambe" rel="nofollow" target="_blank" title=""&gt;Prajakta Tambe&lt;/a&gt; 于 2016.1.11&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Fri, 05 Aug 2016 15:52:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/30745</link>
      <guid>https://ruby-china.org/topics/30745</guid>
    </item>
    <item>
      <title>在 Rails 5 控制器外部渲染视图</title>
      <description>&lt;p&gt;这篇博客是我们 &lt;a href="http://blog.bigbinary.com/categories/Rails-5" rel="nofollow" target="_blank" title=""&gt;《Rails 5 系列文章》&lt;/a&gt; 中的一篇。&lt;/p&gt;

&lt;p&gt;Rails 的「请求 - 响应」周期很好理解。请求击中应用，传递到路由 &lt;code&gt;route.rb&lt;/code&gt;，路由匹配相应的控制器动作，最终由控制器动作处理请求，并基于请求类型渲染 HTML 或 JSON。然而有时候我们想要在这个「请求 - 响应」周期之外去渲染我们的 HTML 或 JSON。比如用户要下载一个网页报告的 PDF 版本，通过「请求 - 相应」周期是能做到的。但要是我们还需发送一个周报给经理并将其作为邮件的附件来发送时，我们就需要生成相同的 PDF，却由于发送邮件是后台任务因此就落到了「请求 - 相应」周期之外了。&lt;/p&gt;

&lt;p&gt;Rails 5 提供了该特性。&lt;/p&gt;

&lt;p&gt;比如我们有一个 &lt;code&gt;OrderController&lt;/code&gt; 且需要在其外部渲染独立的订单。&lt;/p&gt;

&lt;p&gt;启动 &lt;code&gt;rails console&lt;/code&gt; 执行如下命令：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;OrdersController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:show&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;assigns: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;order: &lt;/span&gt;&lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将渲染 &lt;code&gt;app/views/orders/show.html.erb&lt;/code&gt; 并带上值为 &lt;code&gt;Order.last&lt;/code&gt; 的 &lt;code&gt;@order&lt;/code&gt; 变量。可以通过 &lt;code&gt;assigns&lt;/code&gt; 来设置实例变量，就跟在控制器动作中设置它们一样。那些实例变量将被传入到即将被渲染的视图中去。&lt;/p&gt;

&lt;p&gt;渲染局部视图也可以：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;OrdersController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:_form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;locals: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;order: &lt;/span&gt;&lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将渲染 &lt;code&gt;app/views/orders/_form.html.erb&lt;/code&gt; 且将传入本地变量 &lt;code&gt;order&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;再如我要渲染所有订单为 JSON 格式：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;OrdersController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "[{"id":1, "name":"The Well-Grounded Rubyist", "author":"David A. Black"},&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="ss"&gt;:"Remote: Office not required"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"author"&lt;/span&gt;&lt;span class="ss"&gt;:"David &amp;amp; Jason"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;甚至渲染普通文本也行：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;BooksController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;plain: &lt;/span&gt;&lt;span class="s1"&gt;'this is awesome!'&lt;/span&gt;
  &lt;span class="no"&gt;Rendered&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "this is awesome!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类似 &lt;code&gt;text&lt;/code&gt;，我们还可以使用 &lt;code&gt;render file&lt;/code&gt; 和 &lt;code&gt;render template&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="请求环境"&gt;请求环境&lt;/h3&gt;
&lt;p&gt;典型的 web 请求会带上它自己的环境，通常我们在控制器中使用 &lt;code&gt;request.env&lt;/code&gt; 来处理该环境。某些像 &lt;code&gt;devise&lt;/code&gt; 的包依靠 &lt;code&gt;env&lt;/code&gt; 哈希来获取诸如 warden token 的信息。&lt;/p&gt;

&lt;p&gt;Rails 为此提供了一个默认的 rack 环境，通过 &lt;code&gt;renderer.defaults&lt;/code&gt; 可访问它的默认参数。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;OrdersController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defaults&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:http_host&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;"example.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:https&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:method&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:script_name&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:input&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从内部说，Rails 将基于以上参数创建一个新 Rack 环境。&lt;/p&gt;
&lt;h3 id="自定义环境"&gt;自定义环境&lt;/h3&gt;
&lt;p&gt;我们可以使用 &lt;code&gt;renderer&lt;/code&gt; 的方法来自定义环境。比如我们需要「POST 方式」和 要求「HTTPS」作为后台任务处理。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderer&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="ss"&gt;method: &lt;/span&gt;&lt;span class="s1"&gt;'post'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;https: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;ActionController::Renderer:0x007fdf34453f10 @controller=ApplicationController, @defaults={:http_host=&amp;gt;"example.org", :https=&amp;gt;false, :method=&amp;gt;"get", :script_name=&amp;gt;"", :input=&amp;gt;""}, @env={"HTTP_HOST"=&amp;gt;"example.org", "HTTPS"=&amp;gt;"on", "REQUEST_METHOD"=&amp;gt;"POST", "SCRIPT_NAME"=&amp;gt;"", "rack.input"=&amp;gt;""}&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在我们拥有了自定义的 &lt;code&gt;renderer&lt;/code&gt; 用来生成视图：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;template: &lt;/span&gt;&lt;span class="s1"&gt;'show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;locals: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;order: &lt;/span&gt;&lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;总的来说这个是不错的特性，尤其可复用于现有代码。&lt;/p&gt;

&lt;p&gt;作者 &lt;a href="https://github.com/prathamesh-sonpatki" rel="nofollow" target="_blank" title=""&gt;Prathamesh Sonpatki&lt;/a&gt; 于 2016.1.8&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Thu, 04 Aug 2016 11:31:05 +0800</pubDate>
      <link>https://ruby-china.org/topics/30726</link>
      <guid>https://ruby-china.org/topics/30726</guid>
    </item>
    <item>
      <title>Test runner in Rails 5</title>
      <description>&lt;p&gt;这篇博客是我们 &lt;a href="http://blog.bigbinary.com/categories/Rails-5" rel="nofollow" target="_blank" title=""&gt;《Rails 5 系列文章》&lt;/a&gt; 中的一篇。&lt;/p&gt;

&lt;p&gt;在 Rails 5 项目里使用 &lt;code&gt;bin/rails -h&lt;/code&gt;，你将看到跑测试的一个新命令（&lt;code&gt;rails test&lt;/code&gt;）&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails &lt;span class="nt"&gt;-h&lt;/span&gt;
Usage: rails COMMAND &lt;span class="o"&gt;[&lt;/span&gt;ARGS]

The most common rails commands are:
 generate    Generate new code &lt;span class="o"&gt;(&lt;/span&gt;short-cut &lt;span class="nb"&gt;alias&lt;/span&gt;: &lt;span class="s2"&gt;"g"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 console     Start the Rails console &lt;span class="o"&gt;(&lt;/span&gt;short-cut &lt;span class="nb"&gt;alias&lt;/span&gt;: &lt;span class="s2"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 server      Start the Rails server &lt;span class="o"&gt;(&lt;/span&gt;short-cut &lt;span class="nb"&gt;alias&lt;/span&gt;: &lt;span class="s2"&gt;"s"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nb"&gt;test        &lt;/span&gt;Run tests &lt;span class="o"&gt;(&lt;/span&gt;short-cut &lt;span class="nb"&gt;alias&lt;/span&gt;: &lt;span class="s2"&gt;"t"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Rails 5 之前，我们都用 &lt;code&gt;bin/rake test&lt;/code&gt; 来跑测试，现在我们可以使用 &lt;code&gt;bin/rails test&lt;/code&gt; 了。它不仅仅只是替换了原来的 rake 旧命令，而且它背靠了一个取精华于 RSpec，minitest-reporters，maxitest 及其他的 &lt;code&gt;test runner&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;让我们一起看看 &lt;code&gt;bin/rails test&lt;/code&gt; 能做些啥。&lt;/p&gt;
&lt;h3 id="跑单个测试"&gt;跑单个测试&lt;/h3&gt;
&lt;p&gt;现在跑单个测试已经可以使用行号了。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails &lt;span class="nb"&gt;test test&lt;/span&gt;/models/user_test.rb:27
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rails 会机智地运行 user_test.rb 中的第 27 行所在位置的测试。请注意第 27 行甚至不必是该测试的首行，如下例所示：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_valid_user&lt;/span&gt;
&lt;span class="mi"&gt;23&lt;/span&gt;  &lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s1"&gt;'bob@exmaple.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;24&lt;/span&gt;           &lt;span class="ss"&gt;first_name: &lt;/span&gt;&lt;span class="s1"&gt;'John'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;25&lt;/span&gt;           &lt;span class="ss"&gt;last_name: &lt;/span&gt;&lt;span class="s1"&gt;'Smith'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;26&lt;/span&gt;
&lt;span class="mi"&gt;27&lt;/span&gt;  &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;hash&lt;/span&gt;
&lt;span class="mi"&gt;28&lt;/span&gt; 
&lt;span class="mi"&gt;29&lt;/span&gt;  &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valid?&lt;/span&gt;
&lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上例中，只要给出的行号在 22 至 30 之间，&lt;code&gt;test_valid_user&lt;/code&gt; 就会被执行。&lt;/p&gt;
&lt;h3 id="跑多个测试"&gt;跑多个测试&lt;/h3&gt;
&lt;p&gt;你仍可以给出多个路径来跑多个测试。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails &lt;span class="nb"&gt;test test&lt;/span&gt;/models/user_test.rb:27 &lt;span class="nb"&gt;test&lt;/span&gt;/models/post_test.rb:42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;甚至给出多个目录来跑其中的所有测试。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails &lt;span class="nb"&gt;test test&lt;/span&gt;/controllers &lt;span class="nb"&gt;test&lt;/span&gt;/integration
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="错误消息的改善"&gt;错误消息的改善&lt;/h3&gt;
&lt;p&gt;当一个测试失败了，Rails 将显示一行命令用来单独跑错误的那个测试，如：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rails&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="no"&gt;Run&lt;/span&gt; &lt;span class="ss"&gt;options: &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="mi"&gt;51858&lt;/span&gt;

&lt;span class="c1"&gt;# Running:&lt;/span&gt;

&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt;

&lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="no"&gt;PostsControllerTest&lt;/span&gt;&lt;span class="c1"&gt;#test_should_get_new:&lt;/span&gt;
&lt;span class="no"&gt;Expected&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="ss"&gt;:/&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;host&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;


&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rails&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;controllers&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;posts_controller_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我只需拷贝 &lt;code&gt;bin/rails test test/controllers/posts_controller_test.rb:15&lt;/code&gt; 即可重跑错误测试。&lt;/p&gt;
&lt;h3 id="快速报错"&gt;快速报错&lt;/h3&gt;
&lt;p&gt;默认情况，当测试失败，rails 会报告测试失败然后跳到下一个测试。如果你想遇到错误就停下可以添加 &lt;code&gt;-f&lt;/code&gt; 参数。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails t &lt;span class="nt"&gt;-f&lt;/span&gt;
Run options: &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;--seed&lt;/span&gt; 59599

&lt;span class="c"&gt;# Running:&lt;/span&gt;

..F

Failure:
PostsControllerTest#test_should_get_new:
Expected response to be a &amp;lt;success&amp;gt;, but was a &amp;lt;302&amp;gt; redirect to &amp;lt;http://test.host/posts&amp;gt;


bin/rails &lt;span class="nb"&gt;test test&lt;/span&gt;/controllers/posts_controller_test.rb:15

Interrupted. Exiting...


Finished &lt;span class="k"&gt;in &lt;/span&gt;0.179125s, 16.7481 runs/s, 22.3308 assertions/s.

3 runs, 4 assertions, 1 failures, 0 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="延时测试报告输出至整个测试结束"&gt;延时测试报告输出至整个测试结束&lt;/h3&gt;
&lt;p&gt;默认情况，当测试失败，rails 会打印 &lt;code&gt;F&lt;/code&gt; 且详细报告哪个断言出错及如何重测。&lt;/p&gt;

&lt;p&gt;假如你希望一个干净的 &lt;code&gt;.&lt;/code&gt; 和 &lt;code&gt;F&lt;/code&gt; 然后再统一打印错误详情，可以使用 &lt;code&gt;-d&lt;/code&gt; 参数。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails t &lt;span class="nt"&gt;-d&lt;/span&gt;
Run options: &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--seed&lt;/span&gt; 29906

&lt;span class="c"&gt;# Running:&lt;/span&gt;

..F...F

Finished &lt;span class="k"&gt;in &lt;/span&gt;0.201320s, 34.7704 runs/s, 49.6721 assertions/s.

  1&lt;span class="o"&gt;)&lt;/span&gt; Failure:
PostsControllerTest#test_should_create_post &lt;span class="o"&gt;[&lt;/span&gt;/Users/prathamesh/Projects/fun/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:19]:
&lt;span class="s2"&gt;"Post.count"&lt;/span&gt; didn&lt;span class="s1"&gt;'t change by 1.
Expected: 3
  Actual: 2


  2) Failure:
PostsControllerTest#test_should_get_new [/Users/prathamesh/Projects/fun/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:15]:
Expected response to be a &amp;lt;success&amp;gt;, but was a &amp;lt;302&amp;gt; redirect to &amp;lt;http://test.host/posts&amp;gt;

7 runs, 10 assertions, 2 failures, 0 errors, 0 skips

Failed tests:

bin/rails test test/controllers/posts_controller_test.rb:19
bin/rails test test/controllers/posts_controller_test.rb:15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="更好的回溯信息"&gt;更好的回溯信息&lt;/h3&gt;
&lt;p&gt;默认情况，当测试遇到一个错误，输出中并不包含全部的回溯信息，这将使调试变得困难。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error:
PostsControllerTest#test_should_create_post:
NameError: undefined &lt;span class="nb"&gt;local &lt;/span&gt;variable or method &lt;span class="sb"&gt;`&lt;/span&gt;boom&lt;span class="s1"&gt;' for #&amp;lt;PostsController:0x007f86bc62b728&amp;gt;
    app/controllers/posts_controller.rb:29:in `create'&lt;/span&gt;
    &lt;span class="nb"&gt;test&lt;/span&gt;/controllers/posts_controller_test.rb:20:in &lt;span class="sb"&gt;`&lt;/span&gt;block &lt;span class="o"&gt;(&lt;/span&gt;2 levels&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;class:PostsControllerTest&amp;gt;&lt;span class="s1"&gt;'
    test/controllers/posts_controller_test.rb:19:in `block in &amp;lt;class:PostsControllerTest
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当我们使用 &lt;code&gt;-b&lt;/code&gt; 参数后，就会显示完整的错误回溯信息：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails t &lt;span class="nt"&gt;-b&lt;/span&gt;

Error:
PostsControllerTest#test_should_create_post:
NameError: undefined &lt;span class="nb"&gt;local &lt;/span&gt;variable or method &lt;span class="sb"&gt;`&lt;/span&gt;boom&lt;span class="s1"&gt;' for #&amp;lt;PostsController:0x007fc53c4eb868&amp;gt;
    /rails-5-test-runner-app/app/controllers/posts_controller.rb:29:in `create'&lt;/span&gt;
    /sources/rails/actionpack/lib/action_controller/metal/basic_implicit_render.rb:4:in &lt;span class="sb"&gt;`&lt;/span&gt;send_action&lt;span class="s1"&gt;'
    /sources/rails/actionpack/lib/abstract_controller/base.rb:183:in `process_action'&lt;/span&gt;
    /sources/rails/actionpack/lib/action_controller/metal/rendering.rb:30:in &lt;span class="sb"&gt;`&lt;/span&gt;process_action&lt;span class="s1"&gt;'
    /sources/rails/actionpack/lib/abstract_controller/callbacks.rb:20:in `block in process_action'&lt;/span&gt;
    /sources/rails/activesupport/lib/active_support/callbacks.rb:126:in &lt;span class="sb"&gt;`&lt;/span&gt;call&lt;span class="s1"&gt;'
.....
    /sources/rails/activesupport/lib/active_support/testing/assertions.rb:71:in `assert_difference'&lt;/span&gt;
    /rails-5-test-runner-app/test/controllers/posts_controller_test.rb:19:in &lt;span class="sb"&gt;`&lt;/span&gt;block &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;class:PostsControllerTest&amp;gt;&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="借助 Minitest 的力量"&gt;借助 Minitest 的力量&lt;/h3&gt;
&lt;p&gt;测试运行器也会通过提供一些便利参数来借助 minitest 的力量。&lt;/p&gt;
&lt;h5 id="用 -s 开关参数来提供自己的种子值"&gt;用 -s 开关参数来提供自己的种子值&lt;/h5&gt;
&lt;p&gt;现在我们可以用 &lt;code&gt;-s&lt;/code&gt; 开关参数来提供自己的种子值。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails t &lt;span class="nt"&gt;--s&lt;/span&gt; 42000
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;这里补充一下关于 seed 值，由于 minitest 使用 seed 值来随机化测试，因此 seed 值的作用就在于控制随机序列的顺序，也就是说，如果你希望重跑的测试跟上一次的顺序一样，可以设置跟上一次测试相同的 seed 值来做到。详情可以参考 &lt;a href="http://www.mikeperham.com/2012/09/25/minitest-ruby-1-9s-test-framework/" rel="nofollow" target="_blank" title=""&gt;MiniTest&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5 id="用 -n 开关参数来匹配关键字跑测试"&gt;用 -n 开关参数来匹配关键字跑测试&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;-n&lt;/code&gt; 开关参数可以通过给定的字符串或者正则表达式来匹配跑测试&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails t &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"/create/"&lt;/span&gt;
Run options: &lt;span class="nt"&gt;-n&lt;/span&gt; /create/ &lt;span class="nt"&gt;--seed&lt;/span&gt; 24558

&lt;span class="c"&gt;# Running:&lt;/span&gt;

E

Error:
PostsControllerTest#test_should_create_post:
NameError: undefined &lt;span class="nb"&gt;local &lt;/span&gt;variable or method &lt;span class="sb"&gt;`&lt;/span&gt;boom&lt;span class="s1"&gt;' for #&amp;lt;PostsController:0x007faa39c2df90&amp;gt;
    app/controllers/posts_controller.rb:29:in `create'&lt;/span&gt;
    &lt;span class="nb"&gt;test&lt;/span&gt;/controllers/posts_controller_test.rb:20:in &lt;span class="sb"&gt;`&lt;/span&gt;block &lt;span class="o"&gt;(&lt;/span&gt;2 levels&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;class:PostsControllerTest&amp;gt;&lt;span class="s1"&gt;'
    test/controllers/posts_controller_test.rb:19:in `block in &amp;lt;class:PostsControllerTest&amp;gt;'&lt;/span&gt;


bin/rails &lt;span class="nb"&gt;test test&lt;/span&gt;/controllers/posts_controller_test.rb:18

Finished &lt;span class="k"&gt;in &lt;/span&gt;0.073857s, 13.5396 runs/s, 0.0000 assertions/s.

1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="啰嗦输出模式"&gt;啰嗦输出模式&lt;/h5&gt;
&lt;p&gt;使用 &lt;code&gt;-v&lt;/code&gt; 来启用啰嗦输出，它会输出每个测试的运行时间，用来帮助我们判断较慢的测试。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/rails t &lt;span class="nt"&gt;-v&lt;/span&gt;
Run options: &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;--seed&lt;/span&gt; 30118

&lt;span class="c"&gt;# Running:&lt;/span&gt;

PostsControllerTest#test_should_destroy_post &lt;span class="o"&gt;=&lt;/span&gt; 0.07 s &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
PostsControllerTest#test_should_update_post &lt;span class="o"&gt;=&lt;/span&gt; 0.01 s &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
PostsControllerTest#test_should_show_post &lt;span class="o"&gt;=&lt;/span&gt; 0.10 s &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
PostsControllerTest#test_should_create_post &lt;span class="o"&gt;=&lt;/span&gt; 0.00 s &lt;span class="o"&gt;=&lt;/span&gt; F

Failure:
PostsControllerTest#test_should_create_post:
&lt;span class="s2"&gt;"Post.count"&lt;/span&gt; didn&lt;span class="s1"&gt;'t change by 1.
Expected: 3
  Actual: 2

bin/rails test test/controllers/posts_controller_test.rb:19

PostsControllerTest#test_should_get_new = 0.02 s = .
PostsControllerTest#test_should_get_index = 0.01 s = .
PostsControllerTest#test_should_get_edit = 0.00 s = .

Finished in 0.210071s, 33.3220 runs/s, 47.6028 assertions/s.

7 runs, 10 assertions, 1 failures, 0 errors, 0 skips
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="亮彩输出"&gt;亮彩输出&lt;/h3&gt;
&lt;p&gt;现在默认情况下，我们就能得到亮彩输出，无需再添加额外的 gem 了。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.bigbinary.com/assets/rails_5_test_runner-aff8ceb58869d2529c4a2dcc439f2030ec94b7a57799d2c6bc0a467358cf9629.png" title="" alt="Img"&gt;&lt;/p&gt;

&lt;p&gt;拥有了以上这些优秀的特性，无疑改善了 Rails 5 应用的测试体验。Rails 已经整装待发所有以上特性，因此你无需在四处寻找各种包和组件来支持以上功能了。&lt;/p&gt;

&lt;p&gt;作者 &lt;a href="https://github.com/prathamesh-sonpatki" rel="nofollow" target="_blank" title=""&gt;Prathamesh Sonpatki&lt;/a&gt; 于 2016.1.3&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Thu, 04 Aug 2016 10:46:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/30725</link>
      <guid>https://ruby-china.org/topics/30725</guid>
    </item>
    <item>
      <title>ApplicationRecord in Rails 5</title>
      <description>&lt;p&gt;这篇博客是我们 &lt;a href="http://blog.bigbinary.com/categories/Rails-5" rel="nofollow" target="_blank" title=""&gt;《Rails 5 系列文章》&lt;/a&gt; 中的一篇&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblog.rubyonrails.org/2015/12/18/Rails-5-0-beta1/" rel="nofollow" target="_blank" title=""&gt;Rails 5 beta-1&lt;/a&gt; 最近被正式发布，其中有一项可圈可点的变化叫做 &lt;a href="https://github.com/rails/rails/pull/22567" rel="nofollow" target="_blank" title=""&gt;「ApplicationRecord」&lt;/a&gt; 。&lt;/p&gt;

&lt;p&gt;直至 Rails 4.2 所有的 model 均继承自 &lt;code&gt;ActiveRecord::Base&lt;/code&gt;，但从 Rails 5 起，它们将继承自 &lt;code&gt;ApplicationRecord&lt;/code&gt; 。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那 &lt;code&gt;ActiveRecord&lt;/code&gt; 发生了什么（变化）？&lt;/p&gt;

&lt;p&gt;其实改变并不大，以下文件将被自动加入到 Rails 5 项目的 model 中去。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/application_record.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationRecord&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&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;abstract_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这招跟原先继承自 &lt;code&gt;ActiveController::Base&lt;/code&gt; 的 controller 替换为继承自 &lt;code&gt;ApplicationController&lt;/code&gt; 很类似。&lt;/p&gt;

&lt;p&gt;如今的 &lt;code&gt;ApplicationRecord&lt;/code&gt; 将成为一个应用所需的所有自定义和扩展的单一入口，从而替代对 &lt;code&gt;ActiveRecord::Base&lt;/code&gt; 的猴子补丁。&lt;/p&gt;

&lt;p&gt;假如我需要对 &lt;code&gt;ActiveRecord&lt;/code&gt; 增加一些额外的功能，以下是在 Rails 4.2 中的做法：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyAwesomeFeature&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_something_great&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Doing something complex stuff!!"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MyAwesomeFeature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而现在（如果还这么做），&lt;code&gt;ActiveRecord::Base&lt;/code&gt; 将永久的包含 &lt;code&gt;MyAwesomeFeature&lt;/code&gt; 并且所有继承自它的子类都将包含 &lt;code&gt;MyAwesomeFeature&lt;/code&gt;，即便并非所有子类都需要。&lt;/p&gt;

&lt;p&gt;尤其是假如你正在使用的插件或引擎来自被打过猴子补丁的 &lt;code&gt;ActiveRecord::Base&lt;/code&gt; 则会被泄漏到插件和引擎的代码中去。&lt;/p&gt;

&lt;p&gt;但如果使用 &lt;code&gt;ApplicationRecord&lt;/code&gt;，它们将被本地化应用到哪些继承自 &lt;code&gt;ApplicationRecord&lt;/code&gt; 的 model 中去，也就是说只对你自己的程序起作用。（从而不会污染其他插件）&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationRecord&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;MyAwesomeFeature&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;abstract_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="从 Rails 4 迁移"&gt;从 Rails 4 迁移&lt;/h3&gt;
&lt;p&gt;所有新的 Rails 5 项目都默认会有 &lt;code&gt;application_record.rb&lt;/code&gt;。如果你正从 Rails 4 做迁移，那只需创建如下文件至 &lt;code&gt;app/models/application_record.rb&lt;/code&gt;，再将所有 model 的继承父类从  &lt;code&gt;ActiveRecord::Base&lt;/code&gt; 改为 &lt;code&gt;ApplicationRecord&lt;/code&gt; 即可&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/application_record.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationRecord&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&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;abstract_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作者 &lt;a href="https://github.com/prathamesh-sonpatki" rel="nofollow" target="_blank" title=""&gt;Prathamesh Sonpatki&lt;/a&gt; 于 2015.11.28&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Wed, 03 Aug 2016 13:58:48 +0800</pubDate>
      <link>https://ruby-china.org/topics/30711</link>
      <guid>https://ruby-china.org/topics/30711</guid>
    </item>
    <item>
      <title>Rails 5 允许对静态资源文件设置 HTTP 头</title>
      <description>&lt;p&gt;这篇博客是我们 &lt;a href="http://blog.bigbinary.com/categories/Rails-5" rel="nofollow" target="_blank" title=""&gt;《Rails 5 系列文章》&lt;/a&gt; 中的一篇&lt;/p&gt;

&lt;p&gt;让我们先来看看 Rails 4.2.4 应用默认的响应头是如何的：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.bigbinary.com/assets/asset-header/header1-0508b91261b75e1a9ea1e306f813090621f0ba8fccf7c5a5fb1b629c87f5c23e.png" title="" alt="Img"&gt;&lt;/p&gt;

&lt;p&gt;现在，假设我们要设置一个自定义的相应头。很容易，我们只需要在 controller 中添加以下代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'X-Tracking-ID'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'123456'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是我们看到了自定义的头：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.bigbinary.com/assets/asset-header/header2-963c1626d57556a2e99b8feb3a2dfb83dc13e33d268749258742446804c1f8e6.png" title="" alt="Img"&gt;&lt;/p&gt;
&lt;h3 id="为静态资源文件设置自定义响应头"&gt;为静态资源文件设置自定义响应头&lt;/h3&gt;
&lt;p&gt;现在我们需要不仅能对标准 Web 请求设置自定义响应头，而且对静态资源也需要设置。举例来说被本地 Rails 服务跑着的 &lt;code&gt;application.js&lt;/code&gt; 文件。这里该如何设置呢？&lt;/p&gt;

&lt;p&gt;实际上在 Rails 4 中是不可能的，它唯一可以为静态资源的响应头做的设置项只有：&lt;code&gt;Cache-Control&lt;/code&gt; ，如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 在 config/environments/production.rb 加入如下代码行&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;static_cache_control&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'public, max-age=1000'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时我们就为资源文件设置了 &lt;code&gt;Cache-Control&lt;/code&gt; 的值：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.bigbinary.com/assets/asset-header/header3-cb2aab2fc31fd0fad6a3acbfb12f4df0ede8650a4e707fc9fc3693ac6eaccff9.png" title="" alt="Img"&gt;&lt;/p&gt;

&lt;p&gt;除此以外的任何响应头都不行，那是一个限制。&lt;/p&gt;
&lt;h3 id="Rails 应用带着这样的限制活了这么久"&gt;Rails 应用带着这样的限制活了这么久&lt;/h3&gt;
&lt;p&gt;Rails 跑静态资源文件并非强项。那是 Apache 和 Nginx 的拿手好戏。因此，在实际生产环境中，几乎所有人都会在 Rails Server 之前架一道 Apache 或 Nginx 以至于无需用 Rails 来跑静态资源。&lt;/p&gt;

&lt;p&gt;Havig 说，Rails 应用跑在 Heroku 上是个异常。跑在 Heroku 上的 Rails 应用的资源文件其实被 Rails 应用自己在跑着。&lt;/p&gt;
&lt;h3 id="我们遇到的问题"&gt;我们遇到的问题&lt;/h3&gt;
&lt;p&gt;我们的 &lt;a href="http://bigbinary.com/" rel="nofollow" target="_blank" title=""&gt;网站&lt;/a&gt; 是跑在 Heroku 上的。当我们用 &lt;a href="https://developers.google.com/speed/pagespeed/insights/" rel="nofollow" target="_blank" title=""&gt;Google page speed insights&lt;/a&gt; 跑一遍网站，就被警告说我们没有为资源文件设置 &lt;code&gt;Expires&lt;/code&gt; 头。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.bigbinary.com/assets/PageSpeedInsightsWarnings-c2fba3625997dc1363929e01487ffa1133bf853a2acb7a699f964db699c355d9.png" title="" alt="Img"&gt;&lt;/p&gt;

&lt;p&gt;下图显示了 &lt;code&gt;application.js&lt;/code&gt; 的头&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.bigbinary.com/assets/bigbinary_before_expires-9bef61cc02922f59a5d8753417d8d66ca578e73a141dedb94c3dce6ede3c00c1.png" title="" alt="Img"&gt;&lt;/p&gt;

&lt;p&gt;现在你就了解了我们遇到的问题。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;我们的应用跑在 Heroku 上&lt;/li&gt;
&lt;li&gt;Heroku 让 Rails 来跑静态文件&lt;/li&gt;
&lt;li&gt;Google page speed insights 需要我们设置 &lt;code&gt;Expires&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Rails 应用只允许为静态文件设置 &lt;code&gt;Cache-Control&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;一种方案就是将网站放到 &lt;a href="https://www.digitalocean.com/" rel="nofollow" target="_blank" title=""&gt;Digital Ocean&lt;/a&gt; 上在使用 Apache 或者 Nginx。&lt;/p&gt;
&lt;h3 id="Rails 5 拯救了今日"&gt;Rails 5 拯救了今日&lt;/h3&gt;
&lt;p&gt;如今 Rails &lt;a href="https://github.com/rails/rails/pull/19135" rel="nofollow" target="_blank" title=""&gt;整合了头访问控制的基础支持&lt;/a&gt; 并且加入了自定义 HTTP 头的能力。&lt;/p&gt;

&lt;p&gt;场景背后，Rails 使用 &lt;code&gt;ActionDispatch::Static&lt;/code&gt; 中间件来运行静态文件。例如，一个取图片的请求，在请求周期中通过 &lt;code&gt;ActionDispatch::Static&lt;/code&gt;。&lt;code&gt;ActionDispatch::Static&lt;/code&gt; 从响应中带有适当头的服务中运行 &lt;code&gt;Rack:File&lt;/code&gt; 对象。被运行的图片就能拥有类似 &lt;code&gt;Content-Type&lt;/code&gt;，&lt;code&gt;Cache-Control&lt;/code&gt; 等头。&lt;/p&gt;
&lt;h3 id="开始使用最新的 Rails"&gt;开始使用最新的 Rails&lt;/h3&gt;
&lt;p&gt;为了修复该问题，我们使用了最新的 Rails&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;github: &lt;/span&gt;&lt;span class="s1"&gt;'rails/rails'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rack'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;github: &lt;/span&gt;&lt;span class="s1"&gt;'rack/rack'&lt;/span&gt; &lt;span class="c1"&gt;# Rails depends on Rack 2&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'arel'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;github: &lt;/span&gt;&lt;span class="s1"&gt;'rails/arel'&lt;/span&gt; &lt;span class="c1"&gt;# Rails master works alongside of arel master.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着，我们修改配置来提供缺失的 &lt;code&gt;Expires&lt;/code&gt; 头&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# production.rb&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;public_file_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s1"&gt;'Cache-Control'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'public, s-maxage=31536000, maxage=15552000'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s1"&gt;'Expires'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;year&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_formatted_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:rfc822&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里，我们先设置了 &lt;code&gt;Cache-Control&lt;/code&gt; 头来使用公共缓存，&lt;code&gt;maxage&lt;/code&gt; 和 &lt;code&gt;s-maxage&lt;/code&gt; 均设为一年（31536000 秒）。&lt;/p&gt;

&lt;p&gt;然后设置缺失的 &lt;code&gt;Expires&lt;/code&gt; 值，之后我们再次测试就能看到新的头，再没有收到头缺失的警告。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.bigbinary.com/assets/PageSpeedInsightsSolved-76859a9e274b9282f7cc57ecbea563787db14aaf7034f2fc853a6d85ef695917.png" title="" alt="Img"&gt;&lt;/p&gt;

&lt;p&gt;这是改变后的静态文件响应头：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.bigbinary.com/assets/bigbinary_after_expires-b17afb7d23d9d89cdad22dbd754567c843e7847c529f7b5c0a125b84130769b2.png" title="" alt="Img"&gt;&lt;/p&gt;
&lt;h3 id="补充阅读"&gt;补充阅读&lt;/h3&gt;
&lt;p&gt;为更好地使用和了解关于不同头对静态文件的使用细节，敬请参考 &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html" rel="nofollow" target="_blank" title=""&gt;RFC2616&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者 &lt;a href="https://github.com/vipulnsward" rel="nofollow" target="_blank" title=""&gt;Vipul&lt;/a&gt; 于 2015.10.31&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Wed, 03 Aug 2016 11:58:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/30709</link>
      <guid>https://ruby-china.org/topics/30709</guid>
    </item>
    <item>
      <title>🚀 如何编写一个 JS 开源库 (技能包 / 长文)</title>
      <description>&lt;h3 id="引言"&gt;引言&lt;/h3&gt;
&lt;p&gt;GitHub 怎么用？Issue 还能通过 Commit 来同步关闭？版本号是怎么定义的？如何自动发行版本？Commit 还有公约和规范？怎样做持续构建？如何在提交之前就做测试？测试覆盖率是什么？……&lt;/p&gt;

&lt;p&gt;也许在工作中您会遇到诸如此类的问题，不论您是菜鸟还是老手，但愿这篇文章能让你在其中找到一些有价值或可借鉴的东西，这源自一个教我学会「如何编写一个 JS 开源库」的实践项目，同时也让我领悟了许多开源项目的工程管理概念、思路及方法，包括 &lt;strong&gt;版本管理、测试编写、自动版本发行、代码提交公约、持续构建（CI）、提交前测试、测试覆盖率及其报告&lt;/strong&gt; 等，总体感觉受益匪浅，在此对教程原文&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E6%95%99%E7%A8%8B%E5%8E%9F%E6%96%87" title=""&gt;[1]&lt;/a&gt;表示感谢，并决定将视频中的大量知识通过写作记录下来，在学习过程中我也加入了一些自己的思考，将视频内容转换成了更通俗的语言，没时间看视频的朋友兴许可以瞧瞧这里，对于简单的技能可以跳过，相关技能的章节已做了电梯，可以直达进行阅读。&lt;strong&gt;注意&lt;/strong&gt;：在您阅读任何技能章节之前建议您先看看&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E9%A1%B9%E7%9B%AE%E8%83%8C%E6%99%AF" title=""&gt;项目背景&lt;/a&gt;，它非常简单，但它对您理解后面的内容很有帮助。&lt;/p&gt;

&lt;p&gt;它让我学会了以下 &lt;strong&gt;新技能（√）&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;【&lt;a href="#https://github.com/DotHide/starwars-names/tree/master#%E6%8A%80%E8%83%BD-1-%E8%B4%A6%E6%88%B7%E5%BB%BA%E7%AB%8B" title=""&gt;技能 1&lt;/a&gt;】&lt;strong&gt;账户建立&lt;/strong&gt;：建立 GitHub 及 npmjs 账号&lt;/li&gt;
&lt;li&gt;【&lt;a href="#https://github.com/DotHide/starwars-names/tree/master%E6%8A%80%E8%83%BD-2-%E8%B4%A6%E6%88%B7%E9%85%8D%E7%BD%AE" title=""&gt;技能 2&lt;/a&gt;】&lt;strong&gt;账户配置&lt;/strong&gt;：配置 NPM，并构建第一个库&lt;/li&gt;
&lt;li&gt;【&lt;a href="#https://github.com/DotHide/starwars-names/tree/master%E6%8A%80%E8%83%BD-3-%E4%BB%A3%E7%A0%81%E6%8F%90%E4%BA%A4" title=""&gt;技能 3&lt;/a&gt;】&lt;strong&gt;代码提交&lt;/strong&gt;：提交开源库至 GitHub&lt;br&gt;

&lt;ul&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E5%85%8D%E5%AF%86%E7%99%BB%E5%BD%95" title=""&gt;技能 3.1&lt;/a&gt;】免密登录：无需每次输入密码登录 Linux 主机&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E6%8A%80%E8%83%BD-4-%E5%BA%93%E5%8F%91%E5%B8%83" title=""&gt;技能 4&lt;/a&gt;】&lt;strong&gt;库发布&lt;/strong&gt;：将开源库发布到 &lt;a href="https://www.npmjs.com" rel="nofollow" target="_blank" title=""&gt;NPM Repo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E6%8A%80%E8%83%BD-5-%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86" title=""&gt;技能 5&lt;/a&gt;】&lt;strong&gt;版本管理&lt;/strong&gt;：包括版本号定义，版本标签及版本发行&lt;br&gt;

&lt;ul&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E7%89%88%E6%9C%AC%E5%8F%B7%E5%AE%9A%E4%B9%89" title=""&gt;技能 5.1&lt;/a&gt;】版本号定义：版本号每个数字的意义&lt;br&gt;
&lt;/li&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E7%89%88%E6%9C%AC%E6%A0%87%E7%AD%BE" title=""&gt;技能 5.2&lt;/a&gt;】版本标签：为版本加标签发布至 GitHub&lt;br&gt;
&lt;/li&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E7%89%88%E6%9C%AC%E5%8F%91%E8%A1%8C" title=""&gt;技能 5.3&lt;/a&gt;】版本发行：发布一个版本至 NPM&lt;br&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E6%8A%80%E8%83%BD-6-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95" title=""&gt;技能 6&lt;/a&gt;】&lt;strong&gt;单元测试&lt;/strong&gt;：利用 Mocha 和 Chai 建立单元测试&lt;/li&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E6%8A%80%E8%83%BD-7-%E8%87%AA%E5%8A%A8%E7%89%88%E6%9C%AC%E5%8F%91%E8%A1%8C" title=""&gt;技能 7&lt;/a&gt;】&lt;strong&gt;自动版本发行&lt;/strong&gt;：利用 semantic-release 自动化发行&lt;/li&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names/tree/master#%E6%8A%80%E8%83%BD-8-%E4%BB%A3%E7%A0%81%E6%8F%90%E4%BA%A4%E5%85%AC%E7%BA%A6" title=""&gt;技能 8&lt;/a&gt;】&lt;strong&gt;代码提交公约&lt;/strong&gt;：利用 commitizen 编写提交公约&lt;/li&gt;
&lt;li&gt;【&lt;a href="https://github.com/DotHide/starwars-names#%E6%8A%80%E8%83%BD-9-%E6%8C%81%E7%BB%AD%E6%9E%84%E5%BB%BA" title=""&gt;技能 9&lt;/a&gt;】&lt;strong&gt;持续构建（CI）1&lt;/strong&gt;：利用 TravisCI 持续构建&lt;/li&gt;
&lt;li&gt;【技能 10】&lt;strong&gt;提交前测试&lt;/strong&gt;：利用 ghooks 做提交前自动化测试&lt;/li&gt;
&lt;li&gt;【技能 11】&lt;strong&gt;测试覆盖率 1&lt;/strong&gt;：利用 Istanbul 做代码覆盖&lt;/li&gt;
&lt;li&gt;【技能 12】&lt;strong&gt;测试覆盖率 2&lt;/strong&gt;：添加代码覆盖率报告&lt;/li&gt;
&lt;li&gt;【技能 13】&lt;strong&gt;GH 特效&lt;/strong&gt;：在 README 中添加徽章&lt;/li&gt;
&lt;li&gt;【技能 14】&lt;strong&gt;ES6 支持 1&lt;/strong&gt;：添加 ES6 支持&lt;/li&gt;
&lt;li&gt;【技能 15】&lt;strong&gt;ES6 支持 2&lt;/strong&gt;：使用 Mocha &amp;amp; Babel 对测试添加 ES6 支持&lt;/li&gt;
&lt;li&gt;【技能 16】&lt;strong&gt;持续构建（CI）2&lt;/strong&gt;：Travis 上的限制分支构建&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;部分技能章节还在更新中，敬请期待&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;如果您对这篇文章感兴趣，请前往我的 GitHub 项目主页阅读（&lt;a href="https://github.com/DotHide/starwars-names" rel="nofollow" target="_blank" title=""&gt;https://github.com/DotHide/starwars-names&lt;/a&gt;），我将在那里做持续更新，如果您觉得本文有用，请您顺手赏颗⭐️，非常感谢~&lt;/p&gt;

&lt;p&gt;最后，也许您会认为这里是 Ruby 社区，发一篇「如何编写一个 Gem 开源包」也许更有意义，我觉得倒也未必，其中的许多技能它提供了一种思路，至少是一些概念，您完全可以根据这些概念，再写一篇如何编写 Gem 包的文章来：）&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Sun, 28 Feb 2016 20:10:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/29144</link>
      <guid>https://ruby-china.org/topics/29144</guid>
    </item>
    <item>
      <title>JS 简单方法取中文单词的简拼</title>
      <description>&lt;h3 id="主要针对问题"&gt;主要针对问题&lt;/h3&gt;
&lt;p&gt;中文名排序，利用中文名简拼筛选名字或其它中文单词&lt;/p&gt;
&lt;h3 id="示例"&gt;示例&lt;/h3&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;王思聪&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;张柏芝&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;郭德纲&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;林志颖&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;潘长江&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;马云&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;冯小刚&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getShortPinyin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;MAP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ABCDEFGHJKLMNOPQRSTWXYZ&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;boundaryChar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;驁簿錯鵽樲鰒餜靃攟鬠纙鞪黁漚曝裠鶸蜶籜鶩鑂韻糳&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;String.prototype.localeCompare not supported.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^\u&lt;/span&gt;&lt;span class="sr"&gt;4e00-&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="sr"&gt;9fa5&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;boundaryChar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boundaryChar&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zh-CN-u-co-pinyin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;MAP&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;names_with_pinyin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;name_with_pinyin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pinyin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getShortPinyin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;name_with_pinyin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pinyin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cm"&gt;/* Output
** 冯小刚(FXG)
** 郭德纲(GDG)
** 林志颖(LZY)
** 马云(MY)
** 潘长江(PZJ)
** 王思聪(WSC)
** 张柏芝(ZBZ)
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例地址：&lt;a href="https://jsfiddle.net/zhwrkfeh/2/" rel="nofollow" target="_blank"&gt;https://jsfiddle.net/zhwrkfeh/2/&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;_ 使用的是 lodash(&lt;a href="http://lodash.com" rel="nofollow" target="_blank"&gt;http://lodash.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="实现思路"&gt;实现思路&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;将 Unicode 中 GBK 编码方式的字符拿来举例，可以得出连续的汉字是从 \u4e00 到 \u9fa5，因此先判断是在这个范围内的文字&lt;/li&gt;
&lt;li&gt;将这个范围内所有文字拿出来遍历，利用拼音排序，将可以得出每个声母的边界字符：（汉字没有 I U V 这三个声母所以去掉）&lt;/li&gt;
&lt;li&gt;利用 js 提供的字符串函数 localeCompare（需要浏览器支持）跟边界字符比较得出声母&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;驁 (A 的最后一个)&lt;/li&gt;
&lt;li&gt;簿 (B 的最后一个)&lt;/li&gt;
&lt;li&gt;錯 (C 的最后一个)&lt;/li&gt;
&lt;li&gt;鵽 (D 的最后一个)&lt;/li&gt;
&lt;li&gt;樲 (E 的最后一个)&lt;/li&gt;
&lt;li&gt;鰒 (F 的最后一个)&lt;/li&gt;
&lt;li&gt;餜 (G 的最后一个)&lt;/li&gt;
&lt;li&gt;靃 (H 的最后一个)&lt;/li&gt;
&lt;li&gt;攟 (J 的最后一个)&lt;/li&gt;
&lt;li&gt;鬠 (K 的最后一个)&lt;/li&gt;
&lt;li&gt;纙 (L 的最后一个)&lt;/li&gt;
&lt;li&gt;鞪 (M 的最后一个)&lt;/li&gt;
&lt;li&gt;黁 (N 的最后一个)&lt;/li&gt;
&lt;li&gt;漚 (O 的最后一个)&lt;/li&gt;
&lt;li&gt;曝 (P 的最后一个)&lt;/li&gt;
&lt;li&gt;裠 (Q 的最后一个)&lt;/li&gt;
&lt;li&gt;鶸 (R 的最后一个)&lt;/li&gt;
&lt;li&gt;蜶 (S 的最后一个)&lt;/li&gt;
&lt;li&gt;籜 (T 的最后一个)&lt;/li&gt;
&lt;li&gt;鶩 (W 的最后一个)&lt;/li&gt;
&lt;li&gt;鑂 (X 的最后一个)&lt;/li&gt;
&lt;li&gt;韻 (Y 的最后一个)&lt;/li&gt;
&lt;li&gt;糳 (Z 的最后一个)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="相关参考链接"&gt;相关参考链接&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://www.cs.nyu.edu/~yusuke/tools/unicode_to_gb2312_or_gbk_table.html" rel="nofollow" target="_blank" title=""&gt;《Unicode to GB2312 or GBK table》&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="http://www.cnblogs.com/msnadair/archive/2009/04/17/1438320.html" rel="nofollow" target="_blank" title=""&gt;《GB2312-80 范围》举例&lt;/a&gt;&lt;br&gt;
由此范围得出的字符边界示例如下：&lt;a href="https://jsfiddle.net/zhwrkfeh/6/" rel="nofollow" target="_blank"&gt;https://jsfiddle.net/zhwrkfeh/6/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare" rel="nofollow" target="_blank" title=""&gt;「localeCompare 函数参考」&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>dothide</author>
      <pubDate>Fri, 19 Feb 2016 11:44:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/29026</link>
      <guid>https://ruby-china.org/topics/29026</guid>
    </item>
    <item>
      <title>看到这个网站我顿时惊呆了，它有你要的一切一切~</title>
      <description>&lt;h3 id="AWESOME"&gt;AWESOME&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/sindresorhus/awesome" rel="nofollow" target="_blank"&gt;https://github.com/sindresorhus/awesome&lt;/a&gt;
&lt;img src="https://rawgit.com/sindresorhus/awesome/master/media/logo.svg" title="" alt="AWESOME"&gt;&lt;/p&gt;

&lt;p&gt;（本想说点什么，后来想了想什么都不用说了……）&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Thu, 18 Feb 2016 23:18:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/29023</link>
      <guid>https://ruby-china.org/topics/29023</guid>
    </item>
    <item>
      <title>用好你的「一票否决权」—— 分享一款决策量化工具</title>
      <description>&lt;p&gt;在工作中，我们经常会看到一些人行使着「一票否决权」，他们往往是人事经理、采购经理、部门经理等，他们手中握有否决或者枪毙某个人或事的权利，但却没有录取的权利，因为录取可能需要集体投票或者上一级批准，需要经过层层筛选，他们只是其中的一道筛子。那么他们的一票否决就是怎么用的呢？是拍脑袋还是有依据？如果是有依据又是有什么样的依据呢？&lt;/p&gt;

&lt;p&gt;虽然我不知道别人是依据什么来行使这个权利的，但通过日常阅读了解到了一种叫做「指标加权平均量化表」的工具，它是一种非常通用的决策工具，正好可以用来做这样一件事。由于阅读后觉得非常有用，因此做个笔记复习一下，也与大家一同分享。&lt;/p&gt;
&lt;h3 id="正文"&gt;正文&lt;/h3&gt;
&lt;p&gt;举个例子来描述它的工作程序吧：&lt;/p&gt;

&lt;p&gt;正常情况下，如果我根据给定的评价标准来给一个面试者进行打分，可能的情况如下：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th style="text-align:center;"&gt;评价标准&lt;/th&gt;
&lt;th style="text-align:left;"&gt;指标说明&lt;/th&gt;
&lt;th style="text-align:center;"&gt;权重（%）&lt;/th&gt;
&lt;th style="text-align:center;"&gt;评分&lt;/th&gt;
&lt;th style="text-align:center;"&gt;加权分&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;举止仪表&lt;/td&gt;
&lt;td style="text-align:left;"&gt;举止形态，穿衣着装等&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;td style="text-align:center;"&gt;90&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;求职欲望&lt;/td&gt;
&lt;td style="text-align:left;"&gt;想要这份工作的欲望&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;td style="text-align:center;"&gt;80&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;沟通能力&lt;/td&gt;
&lt;td style="text-align:left;"&gt;言语谈吐、沟通表达的能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;td style="text-align:center;"&gt;60&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;逻辑能力&lt;/td&gt;
&lt;td style="text-align:left;"&gt;逻辑分析、理解思维的能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;td style="text-align:center;"&gt;70&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;技术能力&lt;/td&gt;
&lt;td style="text-align:left;"&gt;技术水平及技术可塑性&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;td style="text-align:center;"&gt;80&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;&lt;strong&gt;综合评分&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align:left;"&gt;满分 = 100，&lt;strong&gt;录取底线 = 75.0&lt;/strong&gt;
&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;strong&gt;76.0&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ol&gt;
&lt;li&gt;将评估标准的各项指标列入表格左侧第一栏；&lt;/li&gt;
&lt;li&gt;根据每项指标对面试职位的重要性为其设置权重，将权重填入左数第三栏；&lt;/li&gt;
&lt;li&gt;为每项指标打分，最理想的情况是 100 分；&lt;/li&gt;
&lt;li&gt;计算每项指标的加权分，方法是用该项指标的权重乘以它的得分，然后将加权分填入最右栏；&lt;/li&gt;
&lt;li&gt;最后，将各项指标的加权分相加，最后获得该面试者的加权平均总分；&lt;/li&gt;
&lt;li&gt;将获得的加权平均分与预先设定的总分与预先设定的底线分对比，若低于底线则枪毙；若高于底线，则划入考虑范围，进入下一环节。&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;如果直接求平均分，则会得到结果是 &lt;strong&gt;76&lt;/strong&gt; 分，超过了录取底线分数，但如果是加权平均则结果可能就会不同了，且继续往下看。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;使用该工具的最核心问题就是：如何确定权重？&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;其实我思考后还有一个比较重要的问题：是如何定义评价标准？当然这是另一范畴的内容，需要集思广益和经验积累才列的出来。我们暂且先看确定权重的方法。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;要确定权重，我们需要用到另一个工具&lt;strong&gt;「优化矩阵表」&lt;/strong&gt;，也是一个常用的工具，可以用它来计算权重。具体使用方法如下：&lt;/p&gt;

&lt;p&gt;以下是我的权重设置：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th style="text-align:center;"&gt;决策指标&lt;/th&gt;
&lt;th style="text-align:center;"&gt;举止&lt;/th&gt;
&lt;th style="text-align:center;"&gt;欲望&lt;/th&gt;
&lt;th style="text-align:center;"&gt;沟通&lt;/th&gt;
&lt;th style="text-align:center;"&gt;逻辑&lt;/th&gt;
&lt;th style="text-align:center;"&gt;技术&lt;/th&gt;
&lt;th style="text-align:center;"&gt;得分&lt;/th&gt;
&lt;th style="text-align:center;"&gt;排序&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;举止仪表&lt;/td&gt;
&lt;td style="text-align:center;"&gt;/&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;求职欲望&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;/&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;2&lt;/td&gt;
&lt;td style="text-align:center;"&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;沟通能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;/&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;逻辑能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;/&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;3&lt;/td&gt;
&lt;td style="text-align:center;"&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;技术能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;/&lt;/td&gt;
&lt;td style="text-align:center;"&gt;4&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;假设决策指标就是先前提到的五个，分别将它们置于矩阵表的顶部和左侧，然后用左侧栏的第一项「举止仪表」向右依次与顶部的其余四项对比重要性。若认为「举止仪表」比该项更重要，就在相交的空格中填写「1」，若没有其重要，就填写「0」。&lt;/strong&gt; 依次类推，直至填完右边的三角，由于是方阵，右边三角填完了，左边的三角数值取反即可，对角线是不填的，因此每行应该有 4 个数字，然后横向相加得出每行的得分，排序后就能得到各项指标的优先级了。可以自己先做一份，然后再让跟多的人做，做的人越多权重的结果越有说服力。举例来说：如果 50 个人做完了这样的评分，就可能得到以下这张表「权重计算结果 -50 人」&lt;strong&gt;（非统计数据，是模拟数据）&lt;/strong&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th style="text-align:center;"&gt;评估标准&lt;/th&gt;
&lt;th style="text-align:center;"&gt;我的判断得分&lt;/th&gt;
&lt;th style="text-align:center;"&gt;排序&lt;/th&gt;
&lt;th style="text-align:center;"&gt;群体判断得分&lt;/th&gt;
&lt;th style="text-align:center;"&gt;排序&lt;/th&gt;
&lt;th style="text-align:center;"&gt;权重值 (%)&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;举止仪表&lt;/td&gt;
&lt;td style="text-align:center;"&gt;0&lt;/td&gt;
&lt;td style="text-align:center;"&gt;5&lt;/td&gt;
&lt;td style="text-align:center;"&gt;33&lt;/td&gt;
&lt;td style="text-align:center;"&gt;5&lt;/td&gt;
&lt;td style="text-align:center;"&gt;6.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;求职欲望&lt;/td&gt;
&lt;td style="text-align:center;"&gt;2&lt;/td&gt;
&lt;td style="text-align:center;"&gt;3&lt;/td&gt;
&lt;td style="text-align:center;"&gt;50&lt;/td&gt;
&lt;td style="text-align:center;"&gt;4&lt;/td&gt;
&lt;td style="text-align:center;"&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;沟通能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;4&lt;/td&gt;
&lt;td style="text-align:center;"&gt;150&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;逻辑能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;3&lt;/td&gt;
&lt;td style="text-align:center;"&gt;2&lt;/td&gt;
&lt;td style="text-align:center;"&gt;133&lt;/td&gt;
&lt;td style="text-align:center;"&gt;3&lt;/td&gt;
&lt;td style="text-align:center;"&gt;26.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;技术能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;4&lt;/td&gt;
&lt;td style="text-align:center;"&gt;1&lt;/td&gt;
&lt;td style="text-align:center;"&gt;134&lt;/td&gt;
&lt;td style="text-align:center;"&gt;2&lt;/td&gt;
&lt;td style="text-align:center;"&gt;26.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;可以看出，我的判断与群体之间的差异，然后用群体判断得分的各项分值&lt;strong&gt;除以&lt;/strong&gt;群体判断得分的总分 500 分，得出每项的权重值。由此，我们回到开头的「指标加权平均量化表」，将它填写完成，就会得到如下结果：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th style="text-align:center;"&gt;评价标准&lt;/th&gt;
&lt;th style="text-align:left;"&gt;指标说明&lt;/th&gt;
&lt;th style="text-align:center;"&gt;权重（%）&lt;/th&gt;
&lt;th style="text-align:center;"&gt;评分&lt;/th&gt;
&lt;th style="text-align:center;"&gt;加权分&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;举止仪表&lt;/td&gt;
&lt;td style="text-align:left;"&gt;举止形态，穿衣着装等&lt;/td&gt;
&lt;td style="text-align:center;"&gt;6.6%&lt;/td&gt;
&lt;td style="text-align:center;"&gt;90&lt;/td&gt;
&lt;td style="text-align:center;"&gt;5.94&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;求职欲望&lt;/td&gt;
&lt;td style="text-align:left;"&gt;想要这份工作的欲望&lt;/td&gt;
&lt;td style="text-align:center;"&gt;10%&lt;/td&gt;
&lt;td style="text-align:center;"&gt;80&lt;/td&gt;
&lt;td style="text-align:center;"&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;沟通能力&lt;/td&gt;
&lt;td style="text-align:left;"&gt;言语谈吐、沟通表达的能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;30%&lt;/td&gt;
&lt;td style="text-align:center;"&gt;60&lt;/td&gt;
&lt;td style="text-align:center;"&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;逻辑能力&lt;/td&gt;
&lt;td style="text-align:left;"&gt;逻辑分析、理解思维的能力&lt;/td&gt;
&lt;td style="text-align:center;"&gt;26.6%&lt;/td&gt;
&lt;td style="text-align:center;"&gt;70&lt;/td&gt;
&lt;td style="text-align:center;"&gt;18.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;技术能力&lt;/td&gt;
&lt;td style="text-align:left;"&gt;技术水平及技术可塑性&lt;/td&gt;
&lt;td style="text-align:center;"&gt;26.8%&lt;/td&gt;
&lt;td style="text-align:center;"&gt;80&lt;/td&gt;
&lt;td style="text-align:center;"&gt;21.44&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;&lt;strong&gt;综合评分&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align:left;"&gt;满分 = 100，&lt;strong&gt;录取底线 = 75.0&lt;/strong&gt;
&lt;/td&gt;
&lt;td style="text-align:center;"&gt;100%&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;/td&gt;
&lt;td style="text-align:center;"&gt;&lt;strong&gt;72.0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;进行权重加权平均之后，该面试者的分数没有达到录取底线，因此我们就可以果断地枪毙他了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="小结"&gt;小结&lt;/h3&gt;
&lt;p&gt;「指标加权平均量化表」用之四海而皆宜，从面试、员工绩效到项目评估，加拿大移民局甚至用这一工具来进行移民资格评估。而且如果有兴趣也可以把它用来日常生活中，比如要采购一个大件拿不定注意，犹豫不决的时候倒是可以拿来一试。:-)&lt;/p&gt;

&lt;p&gt;在平时也可以多积累一些权重矩阵，以免要用的时候再想起来去做调研，这里我就借花献佛，邀请大家来做做这个调研，当回收量超过 100 后，我再公布权重结果，也给大家做个参考。&lt;/p&gt;
&lt;h5 id="小调研（希望招聘板块的 HR 们都来参与参与）"&gt;小调研（希望招聘板块的 HR 们都来参与参与）&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;面试评价标准权重调研&lt;/strong&gt; &lt;a href="http://wj.qq.com/survey.html?id=259599&amp;amp;hash=5dae" rel="nofollow" target="_blank" title=""&gt;点此参与&lt;/a&gt;，也可使用微信扫一扫参与&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/06f38f225f42e34b19011350e81a5149.png" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Fri, 22 Jan 2016 17:20:23 +0800</pubDate>
      <link>https://ruby-china.org/topics/28825</link>
      <guid>https://ruby-china.org/topics/28825</guid>
    </item>
    <item>
      <title>Sublime Text 2/3 我的常用设置及插件</title>
      <description>&lt;blockquote&gt;
&lt;p&gt;经常用 Sublime Text III 做开发，用得很愉快，但每次重装系统后，
一系列相关的设置和插件也得重新配置，在此留个档，以便能记住&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="设置文件"&gt;设置文件&lt;/h4&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Preferences.sublime-settings&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 默认字符集&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default_encoding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UTF-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// 主题及配色&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color_scheme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Packages/Theme - Spacegray/base16-eighties.dark.tmTheme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spacegray Eighties.sublime-theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ignored_packages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vintage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// 在文字上双击会全选当前的内容，如果里面出现以下字符，就会被截断&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;word_separators&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;()&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;'-:,.;&amp;lt;&amp;gt;~!@#$%^&amp;amp;*|+=[]{}`~?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// 是否显示行号&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;line_numbers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// 是否显示行号边栏&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gutter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// 行号边栏和文字的间距&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;margin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// 是否显示代码折叠按钮&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fold_buttons&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Tab键制表符宽度&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tab_size&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// 设为true时，缩进和遇到Tab键时使用空格替代&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;translate_tabs_to_spaces&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// 突出显示当前光标所在的行&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;highlight_line&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// 设置光标闪动方式&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;caret_style&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;smooth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="常用插件"&gt;常用插件&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Emmet&lt;/li&gt;
&lt;li&gt;Theme - Spacegray&lt;/li&gt;
&lt;li&gt;Syntax Highlighting for Sass&lt;/li&gt;
&lt;li&gt;Html-CSS-JS Prettify&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>dothide</author>
      <pubDate>Fri, 04 Sep 2015 23:09:02 +0800</pubDate>
      <link>https://ruby-china.org/topics/27191</link>
      <guid>https://ruby-china.org/topics/27191</guid>
    </item>
    <item>
      <title>[上海] 盈科互动 招聘 Ruby 工程师 2 - 3 名 (高级 1 名)</title>
      <description>&lt;h4 id="关于盈科互动"&gt;关于盈科互动&lt;/h4&gt;
&lt;p&gt;上海盈科互动（Wink Interactive）是隶属于健康传播机构（SMW GROUP）的子公司，目前公司只有 11 人，是创业型团队。公司位于上海的腹地黄浦区（Line 9 打浦桥站），交通便利。母公司致力于为中国医学与健康传播事业做贡献，经常承办医疗类行业大会，以及部分医疗行业的专题研讨会等。目前希望研发一款医学远程教育的系统作为战略级产品，用于传播在线医学教育，并将在资源上给予我们支持。此时此刻，我们需要招募 2-3 名志同道合的 Ruby 工程师同我们一起来创造这个产品。目前该产品已经经历了多次迭代开发，尚需逐步完善和创造更多功能。&lt;/p&gt;
&lt;h4 id="职位描述"&gt;职位描述&lt;/h4&gt;
&lt;p&gt;Ruby 工程师，帮助公司完成以上战略级的产品，并在其他相关产品上投入支持。我们的公司的产品范围包括，网站开发、APP 开发、微信开发以及一些小型应用的开发，产品围绕在线教育、会议系统、数码创意产品等&lt;/p&gt;
&lt;h4 id="职位要求"&gt;职位要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;具备扎实的面向对象语言功底，有 Ruby、PHP、JAVA 等语言开发经验的优先考虑&lt;/li&gt;
&lt;li&gt;具备 2 年及以上 Ruby on Rails 开发经验者优先考虑&lt;/li&gt;
&lt;li&gt;具有关系型数据库的设计和开发经验，以 MySQL 为主，了解 MongoDB 者为佳&lt;/li&gt;
&lt;li&gt;熟悉网页前端主流技术（HTML、CSS、JS、jQuery），有 AngularJS、Ionic 开发经验者优先考虑&lt;/li&gt;
&lt;li&gt;熟悉 Linux、Git 为佳&lt;/li&gt;
&lt;li&gt;具备良好的团队意识和协作精神，有较强的沟通能力&lt;/li&gt;
&lt;li&gt;欢迎优秀的计算机专业的应届毕业生&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="薪资福利"&gt;薪资福利&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;税前 6-15K（每年 13 薪，外加一定概率微信年终红包）&lt;/li&gt;
&lt;li&gt;公司根据员工绩效，另有年终绩效奖金&lt;/li&gt;
&lt;li&gt;公司对于工程师上班时间为弹性制，一般在 9:30 - 10:00 到公司即可&lt;/li&gt;
&lt;li&gt;公司办公环境良好，员工关系和谐&lt;/li&gt;
&lt;li&gt;每月都有 TeamBuilding&lt;/li&gt;
&lt;li&gt;另有年度旅游&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="联系方式"&gt;联系方式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;公司名称：上海盈科互动文化传媒有限公司&lt;/li&gt;
&lt;li&gt;公司地址：上海市黄浦区建国西路 91 弄瑞金花园 5 号楼 4 层&lt;/li&gt;
&lt;li&gt;公司主页：&lt;a href="http://www.smw-group.com" rel="nofollow" target="_blank"&gt;http://www.smw-group.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;联系邮箱：dothide@smw-group.com（来信请注明来自 Ruby-China）&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>dothide</author>
      <pubDate>Fri, 31 Jul 2015 13:56:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/26716</link>
      <guid>https://ruby-china.org/topics/26716</guid>
    </item>
    <item>
      <title>我们 Rubyist 怎么跟前端工程师协作？</title>
      <description>&lt;p&gt;最近公司来了一个前端工程师，号称会切页面、CSS、JS 等，但问题来了：他并不会 ruby，以至于很难跟他一起协同开发，他的环境是 Windows + Dreamweaver。&lt;/p&gt;

&lt;p&gt;目前的做法很伤，每次都是我把 ruby 生成的所有页面都静态化，并整理成 web 工程，里面有 images / javascripts / stylesheets 文件夹，他完成后还给我，我还要重新贴到 ruby 工程里去（要知道，光把所有变量都解析成最终值就花了好久，再重新弄回去，我都想自己把他的活干了。）&lt;/p&gt;

&lt;p&gt;更重要的是这样的做法没有版本控制，所有的问题也都将落在我这边，这个过程非常纠结，不知道大伙都是怎么解决这个问题的呢？&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Mon, 06 Jul 2015 20:14:32 +0800</pubDate>
      <link>https://ruby-china.org/topics/26348</link>
      <guid>https://ruby-china.org/topics/26348</guid>
    </item>
    <item>
      <title>发布生产环境时，由于资源使用的是 UPYUN，自动化部署</title>
      <description>&lt;p&gt;由于使用了 UPYUN 做资源存储，替换资源方便不少，在 production.rb 中已经进行了如下设置：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;config.action_controller.asset_host = Settings.upyun_url&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;但每次发布后，都需要重新 FTP 发布资源，在寻求自动化方法的路上，我找到了 &lt;code&gt;gem 'rails-assets-for-upyun', '&amp;gt;= 0.0.9'&lt;/code&gt;，可以用命令上传方便多了，但仍然没有解决自动化部署，于是考虑在 mina 的 deploy.rb 中写一段自动部署脚本，于是就解决了。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# =&amp;gt; Deploy task
# ===========================================================================================
desc "Deploys the current version to the server."
task :deploy =&amp;gt; :environment do
  deploy do
    # Put things that will set up an empty directory into a fully set-up
    # instance of your project.
    invoke :'git:clone'
    invoke :'deploy:link_shared_paths'
    invoke :'bundle:install'
    invoke :'rails:db_migrate'
    invoke :'rails:assets_precompile'
    invoke :'rails:assets_publish_assets_upyun'
    invoke :'deploy:cleanup'

    to :launch do
      invoke :'unicorn:restart'
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace :rails do
  set :publish_upyun, %{
    cd #{app_path}
    bundle exec rake assets:publish_assets_upyun RAILS_ENV=production
  }
  task :assets_publish_assets_upyun do
    queue 'echo "-----&amp;gt; Assets To UPYUN"'
    queue! publish_upyun
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rakefile&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
namespace :assets do
  task :publish_assets_upyun do
    RailsAssetsForUpyun.publish 'bucket', 'username', 'password'
  end
end
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dothide</author>
      <pubDate>Thu, 21 May 2015 10:55:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/25678</link>
      <guid>https://ruby-china.org/topics/25678</guid>
    </item>
    <item>
      <title>[6.4 新加坡] 有参加 RedDotRubyConf 2015 的伙伴吗？</title>
      <description>&lt;p&gt;2015 年 6 月 4-5 日在新加坡举办的 Ruby 大会，有人成团吗？&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.reddotrubyconf.com" rel="nofollow" target="_blank"&gt;http://www.reddotrubyconf.com&lt;/a&gt;&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Sun, 05 Apr 2015 20:29:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/25010</link>
      <guid>https://ruby-china.org/topics/25010</guid>
    </item>
    <item>
      <title>做 Ajax 测试时遇到的问题</title>
      <description>&lt;p&gt;在使用 Minitest 测试框架做测试时遇到一些问题，情况如下&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;个人比较习惯使用 spec 形式，并引入了 Capybara DSL&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在写一个测试时，需要进行一个 click_link，而触发一个 ajax 请求，然后对返回的页面进行断言&lt;/p&gt;

&lt;p&gt;测试是这样写的：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"节目页面跳转相关"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"如果未登录，点击预约报名应该跳转至登录页面"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:program&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;# require_js&lt;/span&gt;
      &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;programs_path&lt;/span&gt;
      &lt;span class="n"&gt;click_link&lt;/span&gt; &lt;span class="s2"&gt;"appointment-program-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"#"&lt;/span&gt;
      &lt;span class="c1"&gt;# wait_for_ajax&lt;/span&gt;
      &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;must_have_selector&lt;/span&gt; &lt;span class="s1"&gt;'h1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Program Index'&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;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ul&amp;gt;
    &amp;lt;% @programs.each do |program| %&amp;gt;
      &amp;lt;li&amp;gt;
        &amp;lt;%= program.title %&amp;gt; &amp;lt;br&amp;gt;
        &amp;lt;%= link_to '报名', '#', 
          :id =&amp;gt; "appointment-program-#{program.id}",
          :onclick =&amp;gt; "programs_index.ajax_post_appoint(#{program.id})" %&amp;gt;
      &amp;lt;/li&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;test_helper 是这样的&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"RAILS_ENV"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../../config/environment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"rails/test_help"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"minitest/rails"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"minitest/rails/capybara"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"minitest/reporters"&lt;/span&gt;

&lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Reporters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Reporters&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ProgressReporter&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="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backtrace_filter&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'database_cleaner'&lt;/span&gt;
&lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:truncation&lt;/span&gt;
&lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clean_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:truncation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ActiveSupport::TestCase&lt;/span&gt;
  &lt;span class="nc"&gt;ActiveRecord::Migration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check_pending!&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Syntax&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Methods&lt;/span&gt;
  &lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_wait_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;require_js&lt;/span&gt;
    &lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current_driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:webkit&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wait_for_ajax&lt;/span&gt;
    &lt;span class="no"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_wait_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jQuery.active'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jQuery.active'&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;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;
    &lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;teardown&lt;/span&gt;
    &lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clean&lt;/span&gt;
    &lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset_session!&lt;/span&gt;
    &lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use_default_driver&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ActionDispatch::IntegrationTest&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DSL&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Assertions&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="问题"&gt;问题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;当我运行测试用例时，由于默认的 Capybara 驱动，所以 &lt;code&gt;wait_for_ajax&lt;/code&gt; 它不认识，不能执行 JS 方法，因此我查文档后发现要在使用 JS 的地方切换成&lt;code&gt;:webkit&lt;/code&gt; 驱动&lt;/li&gt;
&lt;li&gt;当我放开测试用例中的 &lt;code&gt;require_js&lt;/code&gt; 方法时，即使用 &lt;code&gt;:webkit&lt;/code&gt; 驱动后，测试单元测试会变得龟速无比，一个测试要 16s（说好很快的呢）&lt;/li&gt;
&lt;li&gt;而且更奇怪的是，此时 click_link 居然说没有找到该元素，也就是说界面上的 programs 是空数组，明明加了一条数据，这我也是醉了&lt;/li&gt;
&lt;li&gt;由于第 3 条过不去，导致 &lt;code&gt;wait_for_ajax&lt;/code&gt; 根本都执行不到&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;至此已经研究了好几个小时了，实在是束手无策&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Sat, 14 Mar 2015 01:03:30 +0800</pubDate>
      <link>https://ruby-china.org/topics/24644</link>
      <guid>https://ruby-china.org/topics/24644</guid>
    </item>
    <item>
      <title>生产环境上传文件目录最佳实践</title>
      <description>&lt;p&gt;一直在思考一个问题，就是还没找到其最佳实践，问题如下：&lt;/p&gt;

&lt;p&gt;我的项目有上传文件的需求，需要把文件（一般是图片和 PDF），我使用的是 Paperclip，上传至 /public 下的分级目录中，由于我在本地跑开发的时候没有发现问题，便部署到服务器生产环境了（部署使用的是 mina）。&lt;/p&gt;

&lt;p&gt;这时候问题就来了，生产环境里我上传的文件，每当我发布一个新版本的时候，服务器的 current 会指向新版本号的文件夹，以至于我上一版的上传文件都留在了上一版本的文件夹中，目前小弟的解决方法实在不好，就是更新一版，就跑到服务器上去 cp /public 目录。&lt;/p&gt;

&lt;p&gt;希望各路大侠能给小弟支支招，这方面有啥最佳实践能供小弟参考，感激不尽！&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Wed, 04 Mar 2015 14:10:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/24449</link>
      <guid>https://ruby-china.org/topics/24449</guid>
    </item>
    <item>
      <title>high_voltage 组件如果禁用路由，page_path 方法就失效了怎么解？</title>
      <description>&lt;p&gt;小弟使用 high_voltage 组件做了一个 home 页面和一个 welcome 页面，想要实现网站定时开启和关闭，因此有想法是否可以在 pages_controller 中设置 before_action，怎知居然无效，后看 github 得知需要在 high_voltage.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;routes&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;可谁知加入后，page_controller 是生效了，可原先的 page_path 方法居然爆出了 undefind_method 错误，郁闷至极，特此求助！&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Fri, 30 Jan 2015 21:54:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/24033</link>
      <guid>https://ruby-china.org/topics/24033</guid>
    </item>
    <item>
      <title>一句話談 Ruby 入門的標誌</title>
      <description>&lt;p&gt;學了半年的 Ruby 了，也不知道自己算不算入門了，心裡好沒底。大家用一句話來談談心中對於 Ruby 入門的標誌是什麼吧？&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Wed, 24 Sep 2014 18:13:01 +0800</pubDate>
      <link>https://ruby-china.org/topics/21709</link>
      <guid>https://ruby-china.org/topics/21709</guid>
    </item>
    <item>
      <title>【低级问题】su -c 命令执行和直接执行的区别？</title>
      <description>&lt;p&gt;最近小弟部署了应用，发现一个奇葩的问题，在应用根目录直接使用&lt;code&gt;bundle exec unicorn_rails -E production -D -c config/unicorn.rb&lt;/code&gt; 可以正常启动服务器
但是如果使用 &lt;code&gt;su apps -c 'bundle exec unicorn_rails -E production -D -c config/unicorn.rb'&lt;/code&gt;，就会报如下错误：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundler: &lt;span class="nb"&gt;command &lt;/span&gt;not found: unicorn_rails
Install missing gem executables with &lt;span class="s1"&gt;'bundle install'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;真是费解啊，我已经配置好了 rvm，但始终没找到根本原因，求大神帮助&lt;/p&gt;</description>
      <author>dothide</author>
      <pubDate>Sat, 20 Sep 2014 15:00:48 +0800</pubDate>
      <link>https://ruby-china.org/topics/21628</link>
      <guid>https://ruby-china.org/topics/21628</guid>
    </item>
  </channel>
</rss>
