<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>hz_qiuyuanxin (JustQyx)</title>
    <link>https://ruby-china.org/hz_qiuyuanxin</link>
    <description>教育的目的,不是培养人们适应传统的世界,不是着眼于实用性的知识和技能,而要去唤醒学生的力量,培养他们自我学习的主动性,抽象的归纳力和理解力,以便使他们在目前无法预料的种种未来局势中,自我做出有意义的选择</description>
    <language>en-us</language>
    <item>
      <title>[深圳] DJI 大疆创新 互联网团队 招聘 Ruby 高级开发工程师 1 名 (内推 15-40k)</title>
      <description>&lt;h2 id="公司"&gt;公司&lt;/h2&gt;
&lt;p&gt;DJI 大疆创新是全球领先的无人机公司，以“The Future of Possible（未来无所不能）”为理念，不断在各领域开拓创新，目前在全球有 11000 名员工，2017 年销售额破 180 亿元，估值超 150 亿美元。DJI 近几年每年都实现接近翻倍的增长，业务领域也不断拓展，产品目前已经广泛应用在农业、测绘、消防、公共安全、动物保护、地产、能源等多个领域。DJI 目前在控制、算法、通信、IOT 等方向技术积累深厚，在国内可以说难有匹敌。未来大疆将不仅是一家无人机硬件公司，很可能会逐步转变为智能机器人的解决方案公司，通过可以影响三维空间的技术，深刻的改变人类的生活。很多人说大疆在这样一种转型中，互联网、物联网方向的人才可以说是不可或缺。如果你想要跳上一艘正在高速运行的火箭飞船，尝试机遇与挑战并存的职业机会，大疆应该是个很不错的选择。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2019/e04ede69-ad6c-4330-8ac0-9e3147af3295.jpg!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="福利待遇"&gt;福利待遇&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;月薪从 15k-40k 不等，根据各个职位要求以及你的能力所定&lt;/li&gt;
&lt;li&gt;年终丰厚奖金，每个人都不一样，范围取决于你的表现，于我个人而言，每年都有超预期&lt;/li&gt;
&lt;li&gt;每年都有机会获得大疆的内部股，15 年底开始少数员工有机会获得配股，16 年开始比例加大很多，以后每年都有机会，大疆配股未来的价值非常大，所以，越早加入大疆越好&lt;/li&gt;
&lt;li&gt;每年年底都会发出数十台车，从大众高尔夫到奔驰、宝马，只有你足够优秀，就有机会获得这些福利车，而且你还不用担心车牌的问题&lt;/li&gt;
&lt;li&gt;你有机会申请到科技园周边的免费人才房，3 房 2 房单身公寓都有，房租免费，只要付水电物业之类的杂费&lt;/li&gt;
&lt;li&gt;公司有弹性工作制、健身房冲凉房洗衣房、国际幼儿园、公司食堂、上百种各国零食饮料、各种公积金保险、每年体检服务以及可选员工小区住宿等&lt;/li&gt;
&lt;li&gt;每逢节日，公司都会准备丰盛的下午茶，特殊节日还会制作精美的节日礼品发给员工，都是体现公司文化，制作精良，设计优美的礼品&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2019/f6bf1843-6280-4818-8d88-b43f303c4f70.jpg!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="团队简介"&gt;团队简介&lt;/h2&gt;
&lt;p&gt;大疆电商团队，隶属大疆互联网事业部，通过数据、技术和产品服务大疆在线上的所有市场推广和销售业务，进行全球供应链和线上服务体系的建设和规划，持续优化消费客客户体验，对大疆所有硬件产品、软件、增值服务线上营销的商业结果，利润产出，用户体验负责。&lt;/p&gt;

&lt;p&gt;目前大疆在全球超过 50 个国家开展国际电商业务，自建有全球化推广、物流和服务体系。随着用户量、销售额的高速增长，我们不断遇到新的技术挑战，在全球化电商、跨国数据中心、用户体验本土化等方面积累了丰富的经验。希望有更多认同敏捷文化，乐于实践前沿技术与工程实践的小伙伴加入我们，同业务一起高速成长。&lt;/p&gt;
&lt;h2 id="Ruby 高级开发工程师（电商方向，1 名）"&gt;Ruby 高级开发工程师（电商方向，1 名）&lt;/h2&gt;
&lt;p&gt;薪资范围：15k-40k&lt;/p&gt;

&lt;p&gt;工作职责：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;负责大疆电商平台（官网、商城系统、订单系统、支付中心、营销平台等）各业务系统的研发和维护&lt;/li&gt;
&lt;li&gt;定期技术分享及为团队成员进行 Code Review&lt;/li&gt;
&lt;li&gt;指导初中级开发工程师开展工作&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;任职要求：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;2 年以上 Ruby on Rails 开发经验&lt;/li&gt;
&lt;li&gt;熟悉 MySQL、Redis 使用，了解性能优化&lt;/li&gt;
&lt;li&gt;熟悉 HTML、CSS、JavaScript，能独立开发上线完整应用&lt;/li&gt;
&lt;li&gt;有编写自动化测试习惯，熟悉 CI/CD 流程，编码习惯良好&lt;/li&gt;
&lt;li&gt;了解 Web 应用常见漏洞，了解静态漏洞扫描工具，安全意识高&lt;/li&gt;
&lt;li&gt;曾经作为主要开发者参与商业项目，能快速理解业务需求并转化为输出&lt;/li&gt;
&lt;li&gt;了解前端工具链 Node.js、npm/Yarn、Webpack 者优先&lt;/li&gt;
&lt;li&gt;熟悉容器化相关技术，掌握 Docker、K8S 的使用者优先&lt;/li&gt;
&lt;li&gt;有主导开源项目经验，例如提交 PR、Issue，翻译文档者优先&lt;/li&gt;
&lt;li&gt;具备大型电子商务网站、金融行业、银行业、第三方支付等核心系统开发、设计工作经验者优先&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="【联系方式】"&gt;【联系方式】&lt;/h2&gt;
&lt;p&gt;简历请发至 yuanxin.qiu#dji.com，合适的话当天回复，当天内推。&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Tue, 24 Sep 2019 14:55:10 +0800</pubDate>
      <link>https://ruby-china.org/topics/39081</link>
      <guid>https://ruby-china.org/topics/39081</guid>
    </item>
    <item>
      <title>A simple and fast JSON API template engine for Ruby on Rails</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/amatsuda/jb" rel="nofollow" target="_blank"&gt;https://github.com/amatsuda/jb&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A simpler and faster Jbuilder alternative.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我就只是分享不评论 &lt;img title=":grimacing:" alt="😬" src="https://twemoji.ruby-china.com/2/svg/1f62c.svg" class="twemoji"&gt; &lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Tue, 19 Jul 2016 14:35:46 +0800</pubDate>
      <link>https://ruby-china.org/topics/30566</link>
      <guid>https://ruby-china.org/topics/30566</guid>
    </item>
    <item>
      <title>我是这么做登录的图片验证码的</title>
      <description>&lt;p&gt;图片验证码的使用场景就不用说了，在这里分享一下我是如何做登录图片验证码的。&lt;/p&gt;
&lt;h2 id="图片验证码的生成的简单流程"&gt;图片验证码的生成的简单流程&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;生成验证码字符&lt;/code&gt; -&amp;gt; &lt;code&gt;生成图片验证码&lt;/code&gt; [-&amp;gt; &lt;code&gt;使用&lt;/code&gt;]&lt;/p&gt;

&lt;p&gt;第三步的意思是，当你拿到图片验证码时，看你的具体需求了，是直接随着 form 表单渲染，
还是浏览器异步地请求图片验证码，或者其它什么的，反正无所谓了。&lt;/p&gt;
&lt;h2 id="谈一谈 simple_captcha2 的做法"&gt;谈一谈 simple_captcha2 的做法&lt;/h2&gt;
&lt;p&gt;simple_captcha2 是基于 ImageMagick 来生成图片，基于数据库来存储验证码数据的。
提供了 &lt;code&gt;Controller Based&lt;/code&gt; 和 &lt;code&gt;Model Based&lt;/code&gt; 两种用法。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controller Based&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;simple_captcha2 提供了一对方法： &lt;code&gt;show_simple_captcha&lt;/code&gt; 和 &lt;code&gt;simple_captcha_valid?&lt;/code&gt;。
前者是一个 view helper，让我们能够在某个地方显示一张验证码图片，后者让我们可以去判定用户提交的验证码是否正确。
想知道更多的用法可以移步到&lt;a href="https://github.com/pludoni/simple-captcha" rel="nofollow" target="_blank" title=""&gt;它的文档&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;实现原理&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;simple_captcha2 基于数据库维护了一对 key -&amp;gt; value 数据，数据结构如下：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                     Table "public.simple_captcha_data"
   Column   |            Type             |                            Modifiers
------------+-----------------------------+------------------------------------------------------------------
 id         | integer                     | not null default nextval('simple_captcha_data_id_seq'::regclass)
 key        | character varying(40)       |
 value      | character varying(6)        |
 created_at | timestamp without time zone |
 updated_at | timestamp without time zone |
Indexes:
    "simple_captcha_data_pkey" PRIMARY KEY, btree (id)
    "simple_captcha_data_key" btree (key)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当我们调用 &lt;code&gt;show_simple_captcha&lt;/code&gt; 时就会生成一对这样的值，然后存放到数据库（MySQL|Postgresql|Redis），然后在 view 里生成这样的内容。&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&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="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"captcha_key"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"d850ec25ca962ba6606cfe7c84f9568c8473e93e"&lt;/span&gt;
&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;img&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"captcha"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/simple_captcha?code=d850ec25ca962ba6606cfe7c84f9568c8473e93e&amp;amp;time=1431749439"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，它的工作原理就很清楚了。&lt;/p&gt;

&lt;p&gt;key 的生成算法如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Digest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SHA1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s2"&gt;"captcha"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;value 的算法如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_simple_captcha_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'numeric'&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="no"&gt;SimpleCaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;SimpleCaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;chr&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;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;simple_captcha 实现了一个 middleware，以返回验证码图片。&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;SimpleCaptcha&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Middleware&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# :nodoc:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"REQUEST_METHOD"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"GET"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;captcha_path?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'PATH_INFO'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;make_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&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="c1"&gt;# ...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Request&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="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="no"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;simple_captcha_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;send_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generate_simple_captcha_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'image/jpeg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:disposition&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'inline'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:filename&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="s1"&gt;'simple_captcha.jpg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="c1"&gt;#...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在生成验证码图片这一步，它是调用了 ImageMagick 的命令来生成图片的。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected_outcodes&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="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%Q[&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\s+/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; 2&amp;gt;&amp;amp;1"&lt;/span&gt;

  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_magick_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SimpleCaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image_magick_path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_magick_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# convert -size 100x100 -gravity "Center" -implode 0.2 &amp;lt;path/to/file&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;expected_outcodes&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;flatten&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="vg"&gt;$?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exitstatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Error while running &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;output&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;分三步走：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;生成一组 key, value，然后存进数据库&lt;/li&gt;
&lt;li&gt;浏览器根据 key 请求验证码图片&lt;/li&gt;
&lt;li&gt;根据 key 从数据库里取出 value，然后判定用户提交的验证码是否正确&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="我是这么做的"&gt;我是这么做的&lt;/h2&gt;
&lt;p&gt;simple_captcha2 为图片验证码提供了一整套的解决方案，在 Rails 里使用非常简单。
但仍有做得不足的地方，例如没有暴露生成验证码图片的接口给我们，使得我们能够直接通过 ajax 来请求验证码图片。
虽然可以通过 mokey patch 来做的，但是我自己想了一个更简单的方案。&lt;/p&gt;

&lt;p&gt;我的思路：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;生成验证码字符串&lt;/li&gt;
&lt;li&gt;根据字符串生成验证码图片&lt;/li&gt;
&lt;li&gt;将验证码字符串放到 session 里&lt;/li&gt;
&lt;li&gt;将图片编码成 Base64 字符串，剩下的就看你的使用场景&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;伪代码&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# in someone controller&lt;/span&gt;

&lt;span class="c1"&gt;# GET /captcha&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;captcha&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hex&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="nf"&gt;upcase&lt;/span&gt;
  &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:captcha&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
  &lt;span class="n"&gt;base64Image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Captcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;126&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;  &lt;span class="c1"&gt;# 验证码的内容，图片的宽度，图片的高度&lt;/span&gt;
  &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;image: &lt;/span&gt;&lt;span class="n"&gt;base64Image&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最关键的就是如何实现 &lt;code&gt;Captcha.generate&lt;/code&gt; 了，使用纯 Ruby 生成图片成本高，需要许多知识，所以我还是选择了依赖于 ImageMagick。
思路也很简单：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;根据参数，生成关于 ImageMagick 中的 &lt;code&gt;convert&lt;/code&gt; 命令所需要的参数&lt;/li&gt;
&lt;li&gt;使用系统调用来生成图片，并放在一个临时目录里&lt;/li&gt;
&lt;li&gt;读取图片的内容，完成后关闭这个临时文件，最后把图片内容返回&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Captcha&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt;

    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'-fill darkblue'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-background white'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"-size &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"-wave &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;distortion&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'-gravity "Center"'&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'-pointsize 22'&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'-implode 0.2'&lt;/span&gt;

    &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Tempfile&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="s1"&gt;'neolion_captcha'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'.png'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tmpdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;binmode&lt;/span&gt;

    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"label:'&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;#{&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="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&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="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;

    &lt;span class="n"&gt;read_as_base64&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="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;distortion&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;rand&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="mi"&gt;80&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&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="s1"&gt;'x'&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;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected_outcodes&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;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%Q[convert &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\s+/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; 2&amp;gt;&amp;amp;1"&lt;/span&gt;

      &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

      &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;expected_outcodes&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;flatten&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="vg"&gt;$?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exitstatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Error while running &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;output&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;read_as_base64&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;
      &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode64&lt;/span&gt;&lt;span class="p"&gt;(&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;binread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data:image/png;base64,'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&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="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\n/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至于判定用户的验证码是否正确，就很简单了&lt;/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;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;valid_captcha?&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:captcha&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:captcha&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# ...&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;p&gt;要求是 Rails4.x+ 或者是 &lt;code&gt;:db_store&lt;/code&gt;，因为在 Rails 4 之前，如果是 :cookie_store，那么 session 数据在客户端是能够读取的，因为没有加密。&lt;/p&gt;
&lt;h2 id="References"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Digital_image" rel="nofollow" target="_blank"&gt;http://en.wikipedia.org/wiki/Digital_image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.webascender.com/Blog/ID/529/Working-with-Bits-and-Bytes-in-Ruby#.VUuBvROUe58" rel="nofollow" target="_blank"&gt;http://www.webascender.com/Blog/ID/529/Working-with-Bits-and-Bytes-in-Ruby#.VUuBvROUe58&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.imagemagick.org/script/index.php" rel="nofollow" target="_blank"&gt;http://www.imagemagick.org/script/index.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/minimagick/minimagick" rel="nofollow" target="_blank"&gt;https://github.com/minimagick/minimagick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/minimagick/minimagick/issues/59" rel="nofollow" target="_blank"&gt;https://github.com/minimagick/minimagick/issues/59&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wvanbergen/chunky_png" rel="nofollow" target="_blank"&gt;https://github.com/wvanbergen/chunky_png&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wvanbergen/oily_png" rel="nofollow" target="_blank"&gt;https://github.com/wvanbergen/oily_png&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Sat, 16 May 2015 13:38:28 +0800</pubDate>
      <link>https://ruby-china.org/topics/25601</link>
      <guid>https://ruby-china.org/topics/25601</guid>
    </item>
    <item>
      <title>sidekiq jobs 里的竞态问题</title>
      <description>&lt;h2 id="问题"&gt;问题&lt;/h2&gt;
&lt;p&gt;对于单个用户来说，对于其某个资源（例如一个用户的资金、积分等）的更新必须是串行且具备事务。&lt;/p&gt;

&lt;p&gt;例如：当有几个 job 陆续进来，&lt;/p&gt;

&lt;p&gt;change job 1: inc 5 
change job 2: dec 5
change job 3: inc 5
...&lt;/p&gt;

&lt;p&gt;每当一个 job 开始运行前，就必须检查是否有同样的 job【正在或者准备】对同个用户的某个资源进行操作，
如果有，就必须等待其完成后才能进行。&lt;/p&gt;
&lt;h2 id="关于为什么使用 background job 来处理？"&gt;关于为什么使用 background job 来处理？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;业务逻辑较多，需要经过一系列计算才能更新&lt;/li&gt;
&lt;li&gt;用户量较大，要求能支撑起 5W 日活跃用户&lt;/li&gt;
&lt;li&gt;在某些时间段里，用户活跃比较集中&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="unique-jobs ?"&gt;unique-jobs ?&lt;/h2&gt;
&lt;p&gt;虽然 sidekiq 有一些 extensions 如 &lt;code&gt;sidekiq-unique-jobs&lt;/code&gt; 能够控制 job 的 unique，但是它会将后来进来的 job 直接给抛弃掉，
而不是这种必须保证所有 job 的串行执行。&lt;/p&gt;
&lt;h2 id="数据库锁 ?"&gt;数据库锁 ?&lt;/h2&gt;
&lt;p&gt;如果说使用 db row locking，也同样有问题，因为任务必须是 &lt;code&gt;串行执行&lt;/code&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;请问有没有谁有这方面的经验？&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Fri, 04 Jul 2014 12:34:32 +0800</pubDate>
      <link>https://ruby-china.org/topics/20312</link>
      <guid>https://ruby-china.org/topics/20312</guid>
    </item>
    <item>
      <title>Lisp 实现加一操作</title>
      <description>&lt;p&gt;如何理解 &lt;code&gt;lisp&lt;/code&gt; 里加一操作的这个实现？实在理解不了。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Exercise 2.6.  In case representing pairs as procedures wasn't mind-boggling enough, consider that, in a language that can manipulate procedures, we can get by without numbers (at least insofar as nonnegative integers are concerned) by implementing 0 and the operation of adding 1 as&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define&lt;/span&gt; &lt;span class="nv"&gt;zero&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add_1&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Wed, 25 Jun 2014 22:30:09 +0800</pubDate>
      <link>https://ruby-china.org/topics/20169</link>
      <guid>https://ruby-china.org/topics/20169</guid>
    </item>
    <item>
      <title>[已解决] 字符串转二进制数</title>
      <description>&lt;p&gt;有一个二进制字符串数 &lt;code&gt;"1010101001010010010101"&lt;/code&gt;，要怎样才能转成二进制数，然后可以按位做与操作，如：&lt;/p&gt;

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

&lt;p&gt;自己找到一个库：&lt;a href="https://github.com/tyler/bitset" rel="nofollow" target="_blank"&gt;https://github.com/tyler/bitset&lt;/a&gt;&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Tue, 29 Apr 2014 18:55:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/18917</link>
      <guid>https://ruby-china.org/topics/18917</guid>
    </item>
    <item>
      <title>求助：双数据库双时区的问题</title>
      <description>&lt;p&gt;目前项目采用了双数据库：&lt;code&gt;PostgreSQL&lt;/code&gt; 和 &lt;code&gt;MySQL&lt;/code&gt;，但 PostgreSQL 采用的是 PRC 时区，而 MySQL 使用的是 UTC 时区。&lt;/p&gt;

&lt;p&gt;在 &lt;code&gt;config/appliction.rb&lt;/code&gt; 的配置是这样子的：&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;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PRC"&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;time_zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Beijing'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而对于以 MySQL 为 DB 的模型里，我建了一个 source_model.rb 的模型，然后在 model 里去 include 它&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module SourceModel
  extend ActiveSupport::Concern

  included {
    establish_connection "source_#{Rails.env}"
    self.default_timezone = :utc
  }
end

# 引用的例子
class User &amp;lt; ActiveRecord::Base
  include SourceModel
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候问题就出来了，当你调用过 &lt;code&gt;User&lt;/code&gt; 此模型时，AR 所采用的 timezone 就会被变更，而这会影响到以 PSQL 为 DB 的模型，出来的数据的就错，但是又不可能说每次调用前去变更当前的 timezone。&lt;/p&gt;

&lt;p&gt;请问有没有人遇到过并解决了这问题的？还是说只能把 PSQL 的时区也改成 UTC ?&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Tue, 22 Apr 2014 07:41:24 +0800</pubDate>
      <link>https://ruby-china.org/topics/18759</link>
      <guid>https://ruby-china.org/topics/18759</guid>
    </item>
    <item>
      <title>Package old migrations into one</title>
      <description>&lt;p&gt;项目越来越大，自然地，migration 文件就很多了，有没有什么好的方法来打包。&lt;/p&gt;

&lt;p&gt;我自己的思路是：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;新建一个 migration，然后文件的命名为：&lt;code&gt;之前最后一个迁移文件的时间戳_init_tables.rb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;删除以前所有的 migration 文件&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Tue, 08 Apr 2014 14:28:35 +0800</pubDate>
      <link>https://ruby-china.org/topics/18471</link>
      <guid>https://ruby-china.org/topics/18471</guid>
    </item>
    <item>
      <title>Mongid time gt query ？</title>
      <description>&lt;p&gt;如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Tweet&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;span class="nf"&gt;c_at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"2013-09-30 12:39:25 +0800"&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Tweet&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;span class="nf"&gt;c_at&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Mon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="no"&gt;Sep&lt;/span&gt; &lt;span class="mi"&gt;2013&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="no"&gt;CST&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Tweet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;c_at: &lt;/span&gt;&lt;span class="s2"&gt;"2013-09-30 12:39:25 +0800"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Tweet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;c_at: &lt;/span&gt;&lt;span class="s2"&gt;"Mon, 30 Sep 2013 12:39:25 CST +08:00"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于时间格式的不一样，导致比对出来的结果也不一样，请问有人遇到过么？&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Mon, 30 Sep 2013 12:48:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/14487</link>
      <guid>https://ruby-china.org/topics/14487</guid>
    </item>
    <item>
      <title>[Backbone] new collection 问题</title>
      <description>&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Comments&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Collection&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Comment&lt;/span&gt;

  &lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;_counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total_count&lt;/span&gt;
    &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comments&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个 collection fetch 之后，进入这个 parse。&lt;/p&gt;

&lt;p&gt;如果 &lt;code&gt;resp.data.comments&lt;/code&gt; 为空数组的话，那么 &lt;code&gt;collection.models&lt;/code&gt; 里面竟然有一个 &lt;code&gt;comment&lt;/code&gt;，但是没啥数据，导致 render view 的时候，render 出了一个空的 view。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://f.cl.ly/items/3L0T1V1P3G1e3R2g2120/Image%202013.09.25%20%E4%B8%8A%E5%8D%8811%3A01%3A27.png" title="" alt="截图"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://f.cl.ly/items/3H0i2j1c3u2t0W0p2y2h/Image%202013.09.25%20%E4%B8%8A%E5%8D%8811%3A03%3A25.png" title="" alt="截图"&gt;&lt;/p&gt;

&lt;p&gt;看了文档，尝试过返回 &lt;code&gt;[]&lt;/code&gt;、&lt;code&gt;false&lt;/code&gt;、&lt;code&gt;null&lt;/code&gt; 都没用，google 了一把，也没找到相关的。&lt;/p&gt;

&lt;p&gt;请问有没有人也遇到过这个问题？或是有解决方案的？&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Wed, 25 Sep 2013 11:00:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/14377</link>
      <guid>https://ruby-china.org/topics/14377</guid>
    </item>
    <item>
      <title>Mongoid::CounterCache，ruby-china 源码</title>
      <description>&lt;p&gt;今天在开发项目遇到一个问题，即一个模型要按其 embeded document 的 length 排序。&lt;/p&gt;

&lt;p&gt;虽然最简单的就是加一个冗余字段 counter 之类的，但是还是先看看文档和 google 一把，最终还是没找到答案。&lt;/p&gt;

&lt;p&gt;后来想想，ruby-china 源码应该有关于这方面的，哈哈，于是就想看看是怎么做的。&lt;/p&gt;

&lt;p&gt;结果发现也是没有，但是却发现了 CounterCache 这个类，用于 cache 一些 counter。&lt;/p&gt;

&lt;p&gt;代码也是十分简单。&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;Mongoid&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;CounterCache&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;

    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;counter_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;counter_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:inverse_of&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_count"&lt;/span&gt;

        &lt;span class="n"&gt;set_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;relation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;relation&lt;/span&gt;
            &lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&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="n"&gt;counter_name&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="n"&gt;set_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:destroy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;relation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;relation&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&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="n"&gt;counter_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="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;end&lt;/span&gt; &lt;span class="c1"&gt;#ClassMethods&lt;/span&gt;

  &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="c1"&gt;#CounterCache&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="c1"&gt;#Mongoid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用也十分简单，如在 reply 模型里（部分）&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;Reply&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Timestamps&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;BaseModel&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CounterCache&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SoftDelete&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MarkdownBody&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mentionable&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Likeable&lt;/span&gt;

  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:inverse_of&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:replies&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:inverse_of&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:replies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;touch: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;

  &lt;span class="n"&gt;counter_cache&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:inverse_of&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:replies&lt;/span&gt;
  &lt;span class="n"&gt;counter_cache&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:inverse_of&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:replies&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的话，每 create 或者 destroy 一个 reply，则会自动更新 user 和 topic 模型里的 replies_count 这个字段。&lt;/p&gt;

&lt;p&gt;哈哈，打算把这种思路引入到项目里来。&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Mon, 26 Aug 2013 19:26:42 +0800</pubDate>
      <link>https://ruby-china.org/topics/13640</link>
      <guid>https://ruby-china.org/topics/13640</guid>
    </item>
    <item>
      <title>carrierwave 调用 recreate_versions! 时，裁剪后的图片没有被保存</title>
      <description>&lt;p&gt;逻辑大概是这样的，用户上传头像以后，然后就跳转到一个新的页面，然后在那个页面，利用 jcrop 插件，然后提交 crop_x crop_y crop_w crop_h 四个参数，以便后台进行裁剪。&lt;/p&gt;

&lt;p&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;User&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Timestamps&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Short&lt;/span&gt;

  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="n"&gt;mount_uploader&lt;/span&gt; &lt;span class="ss"&gt;:avatar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AvatarUploader&lt;/span&gt;

  &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:crop_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:crop_y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:crop_w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:crop_h&lt;/span&gt;
  &lt;span class="n"&gt;after_update&lt;/span&gt; &lt;span class="ss"&gt;:crop_avatar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;if: :cropping?&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cropping?&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;crop_x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;crop_y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;crop_w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;crop_h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;crop_avatar&lt;/span&gt;
    &lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recreate_versions!&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&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;然后在 AvatarUploader 里大概是这样的：&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;AvatarUploader&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;CarrierWave&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Uploader&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;CarrierWave&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MiniMagick&lt;/span&gt;

  &lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="ss"&gt;:file&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store_dir&lt;/span&gt;
    &lt;span class="c1"&gt;# "uploads/#{model.class.to_s.underscore}/#{model.id}"&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;underscore&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;mounted_as&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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;default_url&lt;/span&gt;
    &lt;span class="n"&gt;_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"default_avatar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"png"&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="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# For Rails 3.1+ asset pipeline compatibility:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;ActionController&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;helpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asset_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"fallback/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;_filename&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="s2"&gt;"/images/fallback/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;version_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"default.png"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;compact&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="s1"&gt;'_'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="ss"&gt;:manual_crop&lt;/span&gt;

  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="ss"&gt;:thumb&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="ss"&gt;resize_to_fit: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="ss"&gt;:mid&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="ss"&gt;resize_to_fit: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="ss"&gt;:large&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="ss"&gt;resize_to_fit: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&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;def&lt;/span&gt; &lt;span class="nf"&gt;extension_white_list&lt;/span&gt;
    &lt;span class="sx"&gt;%w(jpg jpeg gif png)&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;filename&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;original_filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
      &lt;span class="n"&gt;extname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Fiile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Digest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MD5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexdegest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;extname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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;def&lt;/span&gt; &lt;span class="nf"&gt;manual_crop&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cropping?&lt;/span&gt;
      &lt;span class="n"&gt;manipulate!&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;crop&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;crop_w&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;crop_h&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;+&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;crop_x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;+&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;crop_y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;img&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;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Wed, 24 Jul 2013 19:38:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/12749</link>
      <guid>https://ruby-china.org/topics/12749</guid>
    </item>
    <item>
      <title>Rails 将某些页面静态化，在生成文件时遇到的错误</title>
      <description>&lt;p&gt;需要是要将某些网页静态化，但是在写入文件时，发生一个这样的错误！百思不得其解!
&lt;code&gt;"\xE8" from ASCII-8BIT to UTF-8&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;在第一次写入时，由于所有文件都没有，故跑一次没有问题。可是再跑一次，问题就出现了，终端给出了上面说的那个编码的问题！&lt;/p&gt;

&lt;p&gt;&lt;code&gt;builds_static.rb&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# encoding: utf-8&lt;/span&gt;
&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:builds_static&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Generate all builds static pages and save them in /public/builds(rewrite if exist)"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;generate: :environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails/console/app'&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails/console/helpers'&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ConsoleMethods&lt;/span&gt;

    &lt;span class="n"&gt;all_urls_and_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_object&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt; &lt;span class="n"&gt;urls_and_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="c1"&gt;# remember add /builds/index.html&lt;/span&gt;
    &lt;span class="n"&gt;all_urls_and_paths&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;builds_index_url_and_path&lt;/span&gt;
    &lt;span class="n"&gt;generate_static_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_urls_and_paths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;builds_index_url_and_path&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/builds"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"/builds/index.html"&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;def&lt;/span&gt; &lt;span class="nf"&gt;urls_and_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;build_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&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="s2"&gt;"/builds/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;build_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="s2"&gt;"/builds/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;build_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.html"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/builds/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;build_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.plist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="s2"&gt;"/builds/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;build_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.plist"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/apps/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/builds/latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"/builds/apps/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.html"&lt;/span&gt;&lt;span class="p"&gt;]&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;def&lt;/span&gt; &lt;span class="nf"&gt;generate_static_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls_paths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;urls_paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;r&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;open&lt;/span&gt;&lt;span class="p"&gt;(&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;public_path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"w+"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="vg"&gt;$stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Error generating static file &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请问有没有人遇到过这种问题的？&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Mon, 22 Apr 2013 16:12:05 +0800</pubDate>
      <link>https://ruby-china.org/topics/10403</link>
      <guid>https://ruby-china.org/topics/10403</guid>
    </item>
    <item>
      <title>请问有没有专门介绍 Gem 测试的文章的？</title>
      <description>&lt;p&gt;自己写了个 Gem，但是不知道如何写测试！&lt;/p&gt;

&lt;p&gt;请问有没有专门介绍 Gem 测试的文章的？偏原理、概念的&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Fri, 12 Apr 2013 12:16:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/10133</link>
      <guid>https://ruby-china.org/topics/10133</guid>
    </item>
    <item>
      <title>贡献一个 Sublime 自动安装插件脚本</title>
      <description>&lt;p&gt;没技术含量，纯苦力活！&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.config/sublime-text-2/Packages

&lt;span class="nb"&gt;echo &lt;/span&gt;Install...
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;==================================================&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Package Control &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Package Control"&lt;/span&gt;
git clone https://github.com/JustQyx/Sublime-Text-Package-Control.git &lt;span class="s2"&gt;"Package Control"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Block Cursor Everwhere &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Block Cursor Everwhere"&lt;/span&gt;
git clone https://github.com/ingshtrom/BlockCursorEverywhere.git &lt;span class="s2"&gt;"Block Cursor Everwhere"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; CoffeeScript &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"CoffeeScript"&lt;/span&gt;
git clone https://github.com/Xavura/CoffeeScript-Sublime-Plugin.git &lt;span class="s2"&gt;"CoffeeScript"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Compass &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Compass"&lt;/span&gt;
git clone https://github.com/WhatWeDo/Sublime-Text-2-Compass-Build-System.git &lt;span class="s2"&gt;"Compass"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Ctags &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Ctags"&lt;/span&gt;
git clone https://github.com/SublimeText/CTags.git &lt;span class="s2"&gt;"Ctags"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; DictionaryAutoComplete &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"DictionaryAutoComplete"&lt;/span&gt;
git clone https://github.com/Zinggi/DictionaryAutoComplete.git &lt;span class="s2"&gt;"DictionaryAutoComplete"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; GBK Encoding Support &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"GBK Encoding Support"&lt;/span&gt;
git clone https://github.com/akira-cn/sublime-gbk.git &lt;span class="s2"&gt;"GBK Encoding Support"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Git &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Git"&lt;/span&gt;
git clone https://github.com/JustQyx/SublimePluginGit.git &lt;span class="s2"&gt;"Git"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Git Status Files &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Git Status Files"&lt;/span&gt;
git clone https://github.com/mkraft/git-status-files.git &lt;span class="s2"&gt;"Git Status Files"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; LESS &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"LESS"&lt;/span&gt;
git clone https://github.com/danro/LESS-sublime.git &lt;span class="s2"&gt;"LESS"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; PlaceHolders &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"PlaceHolders"&lt;/span&gt;
git clone https://github.com/mrmartineau/Placeholders.git &lt;span class="s2"&gt;"PlaceHolders"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; SCSS &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"SCSS Snippets"&lt;/span&gt;
git clone https://github.com/npostulart/SCSS-Snippets.git &lt;span class="s2"&gt;"SCSS Snippets"&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"SCSS Tm Bundle"&lt;/span&gt;
git clone https://github.com/kuroir/SCSS.tmbundle.git &lt;span class="s2"&gt;"SCSS Tm Bundle"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; ZenCoding &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"ZenCoding"&lt;/span&gt;
git clone https://github.com/sublimator/ZenCoding.git &lt;span class="s2"&gt;"ZenCoding"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Rails File Switcher &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Rails File Switcher"&lt;/span&gt;
git clone https://github.com/AlexanderZaytsev/SublimeText2RailsFileSwitcher.git &lt;span class="s2"&gt;"Rails File Switcher"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Ruby On Rails snippets &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Ruby On Rails snippets"&lt;/span&gt;
git clone https://github.com/tadast/sublime-rails-snippets.git &lt;span class="s2"&gt;"Ruby On Rails snippets"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Rake &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Rake"&lt;/span&gt;
git clone https://github.com/SublimeText/Rake.git &lt;span class="s2"&gt;"Rake"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Rails Related Files &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Rails Related Files"&lt;/span&gt;
git clone https://github.com/luqman/SublimeText2RailsRelatedFiles.git &lt;span class="s2"&gt;"Rails Related Files"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Rails Migrations List &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Rails Migrations List"&lt;/span&gt;
git clone https://github.com/KELiON/RailsMigrationsList.git &lt;span class="s2"&gt;"Rails Migrations List"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Ruby 1.9 Hash Converter &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Ruby 1.9 Hash Converter"&lt;/span&gt;
git clone https://github.com/iltempo/sublime-text-2-hash-syntax.git &lt;span class="s2"&gt;"Ruby 1.9 Hash Converter"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Markdown Preview &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Markdown Preview"&lt;/span&gt;
git clone https://github.com/revolunet/sublimetext-markdown-preview.git &lt;span class="s2"&gt;"Markdown Preview"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Markdown Slideshow &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Markdown Slideshow"&lt;/span&gt;
git clone https://github.com/ogom/sublimetext-markdown-slideshow.git &lt;span class="s2"&gt;"Markdown Slideshow"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; SublimErl &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"SublimErl"&lt;/span&gt;
git clone https://github.com/ostinelli/SublimErl.git &lt;span class="s2"&gt;"SublimErl"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; Prefixr &lt;span class="o"&gt;===&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"Prefixr"&lt;/span&gt;
git clone https://github.com/JustQyx/Sublime-Text-Prefixr.git &lt;span class="s2"&gt;"Prefixr"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;==================================================&lt;/span&gt;
&lt;span class="nb"&gt;echo &lt;/span&gt;Done!
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Usage"&gt;Usage&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Save as sublime-plugin-install.sh&lt;/li&gt;
&lt;li&gt;chmod +x sublime-plugin-install.sh&lt;/li&gt;
&lt;li&gt;./sublime-plugin-install.sh&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Sat, 06 Apr 2013 01:48:19 +0800</pubDate>
      <link>https://ruby-china.org/topics/9980</link>
      <guid>https://ruby-china.org/topics/9980</guid>
    </item>
    <item>
      <title>jQuery 少见的 bind 写法</title>
      <description>&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ajax:success&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我上&lt;code&gt;api.jquery.com&lt;/code&gt;，都找不到有这样的介绍，哪位大侠能指出它的出处啊！&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Wed, 06 Mar 2013 19:16:39 +0800</pubDate>
      <link>https://ruby-china.org/topics/9195</link>
      <guid>https://ruby-china.org/topics/9195</guid>
    </item>
    <item>
      <title>rails_kindeditor 的问题</title>
      <description>&lt;p&gt;我找了个 gem，名为&lt;code&gt;rails_kindeditor&lt;/code&gt;，&lt;/p&gt;

&lt;p&gt;但是尝试获取它的值的时候，无论是用 form 还是尝试用 jquery 去获取都不行。&lt;/p&gt;

&lt;p&gt;查看了它生成后的 html 源代码，还是没有找到方法。&lt;/p&gt;

&lt;p&gt;请有使用过的人指点一下！！&lt;/p&gt;

&lt;p&gt;插件源代码：&lt;a href="https://github.com/Macrow/rails_kindeditor" rel="nofollow" target="_blank"&gt;https://github.com/Macrow/rails_kindeditor&lt;/a&gt;&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Mon, 04 Feb 2013 15:31:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/8594</link>
      <guid>https://ruby-china.org/topics/8594</guid>
    </item>
    <item>
      <title>Rails 与 Excel 日期问题</title>
      <description>&lt;p&gt;近日发现一个问题。&lt;/p&gt;

&lt;p&gt;在 excel 保存日期，都是已 1991 年 1 月 1 日算起，到输入日期的天数来保存的。如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;41046&lt;/span&gt;
&lt;span class="mi"&gt;41046&lt;/span&gt;
&lt;span class="mi"&gt;41051&lt;/span&gt;
&lt;span class="mi"&gt;41051&lt;/span&gt;
&lt;span class="mi"&gt;41046&lt;/span&gt;
&lt;span class="mi"&gt;41046&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是发现 Rails 创建的时候，会出错
&lt;code&gt;Date.new(41046)&lt;/code&gt;，结果是  &lt;code&gt;41026 1 1&lt;/code&gt;，即 4102 年 1 月 1 日。&lt;/p&gt;

&lt;p&gt;请问要怎么处理这问题？&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Sun, 14 Oct 2012 11:35:53 +0800</pubDate>
      <link>https://ruby-china.org/topics/6046</link>
      <guid>https://ruby-china.org/topics/6046</guid>
    </item>
    <item>
      <title>[请教] Rails 统一登录认证</title>
      <description>&lt;p&gt;现在有一个需求，我们给企业做了两个系统，企业希望一次登录，就可以进入两个系统。&lt;/p&gt;

&lt;p&gt;即需要一个类似门户的东西，我在网上看了下，称为&lt;code&gt;统一登录认证&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;请问 Rails 有没有关于这方面的插件或者啥的？&lt;/p&gt;

&lt;p&gt;哪位大侠能给点建议&lt;/p&gt;

&lt;p&gt;Thanks !&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Sat, 22 Sep 2012 15:42:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/5690</link>
      <guid>https://ruby-china.org/topics/5690</guid>
    </item>
    <item>
      <title>[求助] JS 条码打印机</title>
      <description>&lt;p&gt;现在因为项目 (B/S) 需要用到条码打印机。&lt;/p&gt;

&lt;p&gt;所采用的条码打印机是&lt;code&gt;Zebra TLP3844-Z&lt;/code&gt;，斑马系列的打印机有自己的编程语言&lt;code&gt;ZPL(Zebra Programming Language)&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;要打印标签，只要将&lt;code&gt;ZPL指令&lt;/code&gt;(如下) 发送到条码打印机对应的端口即可！&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;XA&lt;/span&gt; 
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;LH300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; 
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;BY2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt; 
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;FO10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;BAN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;N&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;FDCP121001&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;FS&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;FO80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;A0N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;FDCP121001&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;FS&lt;/span&gt; 
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="no"&gt;XZ&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以现在的问题就是如何用&lt;code&gt;Javascript&lt;/code&gt;将这些指令送到&lt;code&gt;条码打印机&lt;/code&gt;那里去。&lt;/p&gt;

&lt;p&gt;求高手帮帮忙！&lt;/p&gt;

&lt;p&gt;谢谢！&lt;/p&gt;</description>
      <author>hz_qiuyuanxin</author>
      <pubDate>Fri, 27 Jul 2012 16:00:10 +0800</pubDate>
      <link>https://ruby-china.org/topics/4599</link>
      <guid>https://ruby-china.org/topics/4599</guid>
    </item>
  </channel>
</rss>
