<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>night_7th</title>
    <link>https://ruby-china.org/night_7th</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>网易蜂巢对象存储服务 (NOS) 的 Carrierwave 插件</title>
      <description>&lt;p&gt;模仿&lt;a href="https://github.com/huacnlee/carrierwave-aliyun" rel="nofollow" target="_blank" title=""&gt;阿里云&lt;/a&gt;的 carrierwave 插件，写了一版&lt;a href="https://c.163.com/product/nos" rel="nofollow" target="_blank" title=""&gt;网易 NOS&lt;/a&gt;的 Carrierwave 插件。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yangsr/carrierwave-nos" rel="nofollow" target="_blank"&gt;https://github.com/yangsr/carrierwave-nos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;当前能够满足我自己的使用了，如果有人遇到问题或者有新需求可以反馈给我&lt;img title=":blush:" alt="😊" src="https://twemoji.ruby-china.com/2/svg/1f60a.svg" class="twemoji"&gt; &lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Fri, 21 Jul 2017 14:58:36 +0800</pubDate>
      <link>https://ruby-china.org/topics/33573</link>
      <guid>https://ruby-china.org/topics/33573</guid>
    </item>
    <item>
      <title>Rack BUFSIZE 导致大文件上传很慢</title>
      <description>&lt;h4 id="问题描述"&gt;问题描述&lt;/h4&gt;
&lt;p&gt;最近在开发一个文件上传功能，开发环境下，上传一个 100 多 M 的文件到服务端，需要花费接近 1 分钟。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/39c1cf78-4754-4ae2-ae12-b2f39d545d27.png!large" title="" alt="file_upload"&gt;&lt;/p&gt;

&lt;p&gt;前端代码是自己写的，也没有用第三方文件上传插件，普通的 jquery，大致长这样：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 开始上传&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;form_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;form_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&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;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/apps/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;form_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;balabala&lt;/span&gt;&lt;span class="p"&gt;...&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 plaintext"&gt;&lt;code&gt;Completed 200 OK in 3786ms (Views: 0.2ms | ActiveRecord: 1131.2ms)
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="尝试解决"&gt;尝试解决&lt;/h4&gt;
&lt;p&gt;花了俩小时放狗搜，最后发现可能是 Rack 的问题：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Rack::Multipart::Parser.parse&lt;/code&gt;中有一个&lt;a href="https://github.com/rack/rack/blob/master/lib/rack/multipart/parser.rb#L70" rel="nofollow" target="_blank" title=""&gt;循环&lt;/a&gt;，每次读取的 BUFSIZE 大小是 16384 个字节。所以文件很大的话，循环得就很多次了。&lt;/p&gt;

&lt;p&gt;已经有人给 Rack 提了一个&lt;a href="https://github.com/rack/rack/issues/1075" rel="nofollow" target="_blank" title=""&gt;issue&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;解决方案也很简单，一位叫 darfux 的同学给出来了，写一个中间件把那个 BUFSIZE 变量覆写掉就好&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;MultipartBufferSetter&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&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="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&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;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="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge!&lt;/span&gt;&lt;span class="p"&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;RACK_MULTIPART_BUFFER_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是按照常理去理解，BUFSIZE 设置为 16384 应当是有原因的，现在被改得这么大有没有潜在的问题还需要观察一阵子，之前使用了 jquery-file-upload 这类第三方插件就没有遇到过这个问题。&lt;img title=":fearful:" alt="😨" src="https://twemoji.ruby-china.com/2/svg/1f628.svg" class="twemoji"&gt; &lt;/p&gt;
&lt;h4 id="更新1"&gt;更新 1&lt;/h4&gt;
&lt;p&gt;今天早上查了下，jquery-file-upload 这个 js 插件有一个特性：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Chunked uploads:
Large files can be uploaded in smaller chunks with browsers supporting the Blob API.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>night_7th</author>
      <pubDate>Tue, 18 Jul 2017 17:27:26 +0800</pubDate>
      <link>https://ruby-china.org/topics/33545</link>
      <guid>https://ruby-china.org/topics/33545</guid>
    </item>
    <item>
      <title>请教重复代码的组织问题</title>
      <description>&lt;p&gt;我们组的情况是这样的，我们根据【面向的用户】区分，将项目划分为对内/对外两个项目，这两个项目共用一个数据库。对外项目主要负责外部用户提交需求，对内项目包括内部工程人员处理需求和一些管理员相关的功能。&lt;/p&gt;

&lt;p&gt;随着代码的积累和增长，对内/对外项目中出现了许多重复的代码：包括 models/helpers/views 里的诸多文件。比较典型的是一个报告展示页面（对内工程师需要审核报告后发布给外部用户看，因此对内/对外都需要报告展示），报告展示功能涉及到两个工程中许多 model/helper，这些对象中的绝大多数方法都是重复的。&lt;/p&gt;

&lt;p&gt;为了解决代码重复的这个困扰，我们引入了&lt;code&gt;git subtree&lt;/code&gt;功能，将重复的 model/helper 移动到了&lt;code&gt;对外项目&lt;/code&gt;的一个共享文件夹。可是渐渐又出现了一个困惑：可能某个同学只是需要修改&lt;code&gt;对内项目&lt;/code&gt;的某个功能，却需要在&lt;code&gt;对外项目&lt;/code&gt;中去修改代码，然后上线时同时更新对内/对外两个项目的代码。而且由于&lt;code&gt;git subtree&lt;/code&gt;的使用经验不足，经常会出现各种奇怪的报错。也有同学担心改动出错影响到两个项目，不敢轻易去改共享文件夹中的代码。&lt;/p&gt;

&lt;p&gt;我自己整理了下目前的几点困惑/思路：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;git subtree 的使用姿势是不是有问题&lt;/li&gt;
&lt;li&gt;将对内/对外两个项目合并，可以减少重复代码，但是项目体积又会膨胀&lt;/li&gt;
&lt;li&gt;服务拆分，或者微服务的思路&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这样类似的问题社区中的一些同学也许遇到过、实践过。想请教大家分享/探讨下类似问题的解决思路。&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Wed, 31 May 2017 11:14:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/33100</link>
      <guid>https://ruby-china.org/topics/33100</guid>
    </item>
    <item>
      <title>这种多对多的设计是否常见</title>
      <description>&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# members表
id BIGINT(20)
user_id BIGINT(20)
app_id BIGINT(20)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们的登陆使用了第三方的登陆系统，会生成一串 hash 存储在 users 表中的一个字段中。&lt;/p&gt;

&lt;p&gt;于是有人建议改成这样的设计：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# members表
id BIGINT(20)
user_hash VARCHAR(255)
app_id BIGINT(20)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;想请问一下大家第二种方案 rails 的支持好么？在多对多的关系设计中是否常见？&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Tue, 02 Aug 2016 11:49:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/30692</link>
      <guid>https://ruby-china.org/topics/30692</guid>
    </item>
    <item>
      <title>Redis 使用及源码的一些疑惑</title>
      <description>&lt;p&gt;最近准备使用 sidekiq 做异步队列，sidekiq 又基于 Redis，我对于 Redis 并不是很熟悉，现在遇到一些问题想请教一下大家：&lt;/p&gt;

&lt;p&gt;1.我们现在已经使用了一个 Redis 用于存储 session，以及同系统其他组件打交道，那 sidekiq 的 Redis 是需要一个新的 Redis 呢，还是使用已有的 Redis 呢，我担心会不会有一些冲突。&lt;/p&gt;

&lt;p&gt;2.因为公司原因，我们需要使用公司内别的部门提供的 Redis 服务，当前我们申请的是一个分布式的 Redis，结果在本地调试连接这个分布式的 Redis 时 sidekiq 报错了，一处是调用了&lt;code&gt;info&lt;/code&gt;方法，另外一处是调用了 Redis 的&lt;code&gt;brpop&lt;/code&gt;方法，这两个方法分布式的 Redis 均不支持，而且一旦调用了，Redis 就自动把连接给断开了。&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;retrieve_work&lt;/span&gt;
  &lt;span class="c1"&gt;# 这里调用了brpop&lt;/span&gt;
  &lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redis&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;brpop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;queues_cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="no"&gt;UnitOfWork&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;work&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;work&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个地方我也有困惑，我查了下&lt;code&gt;brpop&lt;/code&gt;，是一个阻塞型方法，是不是分布式的系统很难实现阻塞型方法呢？因为我看了下公司分布式 Redis 的文档，不支持的指令列表中好几个指令都是 b 开头的。&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Tue, 12 Apr 2016 20:04:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/29687</link>
      <guid>https://ruby-china.org/topics/29687</guid>
    </item>
    <item>
      <title>关于 Don't rescue Exception 的疑问</title>
      <description>&lt;p&gt;今天看到了&lt;code&gt;Rails Best Practice&lt;/code&gt;中的这么一条建议，&lt;a href="http://rails-bestpractices.com/posts/2012/11/01/don-t-rescue-exception-rescue-standarderror/" rel="nofollow" target="_blank" title=""&gt;Don't rescue Exception&lt;/a&gt;：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't rescue Exception, rescue StandardError
Explicitly rescuing Exception will rescue even not normally recoverable errors such as SyntaxError, LoadError, and Interrupt.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;然而我自己在 demo 项目中测试了一下：&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;index&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# Syntax error here&lt;/span&gt;
  &lt;span class="vi"&gt;@books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
  &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;e&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行项目时却正常报错了，并没有被 rescue：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SyntaxError (/app/controllers/books_controller.rb:7: syntax error, unexpected ')', expecting keyword_end
    a )= 2
       ^):

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我的 rails 版本是 4.2.5，很好奇是否这条规则已经失效了。&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Tue, 19 Jan 2016 20:39:08 +0800</pubDate>
      <link>https://ruby-china.org/topics/28784</link>
      <guid>https://ruby-china.org/topics/28784</guid>
    </item>
    <item>
      <title>请教如何设置 API 项目版本相关的路由</title>
      <description>&lt;p&gt;最近接手一项工作，是为部门内部使用的 JIRA 补充一些 API，原有 JIRA API 的格式是这样的：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://jira.mycompany.com/rest/api/latest/search?jql=相关查询语句
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我希望我补充的 API 的格式和原有保持一致，于是我在&lt;code&gt;routes.rb&lt;/code&gt;中是这么设置的：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:rest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:api&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:v1&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'/search'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'issues#search'&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="c1"&gt;# 我希望latest自动指向v1版本下的controller处理&lt;/span&gt;
      &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s1"&gt;'latest/*path'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="n"&gt;redirect&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="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"/rest/api/v1/&lt;/span&gt;&lt;span class="si"&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;:path&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query_string&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="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;via: :get&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;然而当我去调用 api 的时候，如果调用的地址格式是&lt;code&gt;/rest/api/v1/search?jql=查询语句&lt;/code&gt;，那么返回是 200，一切 OK。
当我去调用&lt;code&gt;/rest/api/latest/search?jql=查询语句&lt;/code&gt;的时候：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'localhost:4000/rest/api/latest/search?jql=查询语句'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 web 端看一切正常，也重定向到了我所希望的地址。可是由于使用了重定向，导致了返回值是 301。&lt;/p&gt;

&lt;p&gt;可是我观察原有 JIRA API 的情况，它在调用&lt;code&gt;/rest/api/latest/search?jql=查询语句&lt;/code&gt;的时候，http code 返回值依然是 200。&lt;/p&gt;

&lt;p&gt;想请教一下大家，API 项目中，这种&lt;code&gt;latest&lt;/code&gt;指向某一版本的情况是怎样实现的？&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Tue, 27 Oct 2015 20:59:08 +0800</pubDate>
      <link>https://ruby-china.org/topics/27856</link>
      <guid>https://ruby-china.org/topics/27856</guid>
    </item>
    <item>
      <title>微信开放平台 Omniauth 探索</title>
      <description>&lt;h3 id="准备"&gt;准备&lt;/h3&gt;
&lt;p&gt;最近在折腾网站的微信登录功能，最终希望实现的效果是类似&lt;a href="https://passport.yhd.com/passport/login_input.do" rel="nofollow" target="_blank" title=""&gt;一号店这样的微信登录&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;为此首先需要在&lt;a href="https://open.weixin.qq.com/" rel="nofollow" target="_blank" title=""&gt;微信开放平台&lt;/a&gt;上注册开发者账号，创建网站应用，获得对应的 AppID 和 AppSecret，并申请微信登录接口。在这个过程中，会被要求填写网站信息，包括授权回调域和官网网址。&lt;/p&gt;

&lt;p&gt;这里需要注意的是授权回调域的填写，刚开始我是这么填写的：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.com/auth/wechat/callback
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然而这么填写将会在后面的 OAuth 认证时提示 redirect_uri 参数错误。微信开放平台并没有给出授权回调域的官方填写说明，我是在&lt;a href="https://mp.weixin.qq.com/" rel="nofollow" target="_blank" title=""&gt;微信公众平台&lt;/a&gt;的开发者文档里看到了这么一段话：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;关于网页授权回调域名的说明&lt;/p&gt;

&lt;p&gt;请注意，这里填写的是域名（是一个字符串），而不是 URL，因此请勿加 http://等协议头；&lt;/p&gt;

&lt;p&gt;授权回调域名配置规范为全域名，比如需要网页授权的域名为：www.qq.com，配置以后此域名下面的页面&lt;a href="http://www.qq.com/music.html" rel="nofollow" target="_blank"&gt;http://www.qq.com/music.html&lt;/a&gt; 、 &lt;a href="http://www.qq.com/login.html" rel="nofollow" target="_blank"&gt;http://www.qq.com/login.html&lt;/a&gt; 都可以进行 OAuth2.0 鉴权。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;哦，原来改成这样就可以了：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.com
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="调试"&gt;调试&lt;/h3&gt;
&lt;p&gt;接下来，我想的是到底该如何调试，因为授权回调域不能填成 localhost，总不至于在线上调试吧。&lt;/p&gt;

&lt;p&gt;搜索后发现有人推荐一款叫 ngrok 的软件，只需要注册并下载 ngrok，就可以通过 ngrok 获得一个外网域名，而这个外网域名实际访问的是本地主机。&lt;/p&gt;

&lt;p&gt;具体 ngrok 的注册下载流程省略，按照&lt;a href="https://ngrok.com/" rel="nofollow" target="_blank" title=""&gt;ngrok 官网&lt;/a&gt;一步步来就可以了，这里需要自带梯子。&lt;/p&gt;

&lt;p&gt;之后本地执行&lt;code&gt;./ngrok http -subdomain=example 3000&lt;/code&gt;，出现下面的画面就算成功啦：
&lt;img src="https://l.ruby-china.com/photo/2015/59228ed36e9c2441033a3f1242fb00c1.png" title="" alt="ngrok"&gt;
那么开发阶段，就把刚才提到的授权回调域改成自己设定的 ngrok 地址吧。&lt;/p&gt;
&lt;h3 id="OAuth流程"&gt;OAuth 流程&lt;/h3&gt;
&lt;p&gt;整个微信登录的流程是如下图所示的：
&lt;img src="https://l.ruby-china.com/photo/2015/b4d3151c2a7209656f9cfff47fdbb279.png" title="" alt="wechat-auth-process"&gt;&lt;/p&gt;

&lt;p&gt;OAuth 过程可以使用 omniauth，omniauth 是一个利用 Rack 中间件实现的灵活的认证系统。&lt;/p&gt;

&lt;p&gt;omniauth 需要结合具体平台的 strategy 使用，比如你需要做 github 账号的登录，那就需要&lt;a href="https://github.com/intridea/omniauth-github" rel="nofollow" target="_blank" title=""&gt;omniauth-github&lt;/a&gt;这个 gem。omniauth 官方列出了社区维护的各个平台的&lt;a href="https://github.com/intridea/omniauth/wiki/List-of-Strategies" rel="nofollow" target="_blank" title=""&gt;strategy list&lt;/a&gt;，我在 list 中找到了微信的 omniauth strategy：&lt;a href="https://github.com/skinnyworm/omniauth-wechat-oauth2" rel="nofollow" target="_blank" title=""&gt;omniauth-wechat-oauth2&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;具体怎么使用应该首先看看 README 的文档，我读到了这么一句话：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You need to get a wechat API key at: &lt;a href="http://mp.weixin.qq.com" rel="nofollow" target="_blank"&gt;http://mp.weixin.qq.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这不是微信公众平台的地址么，可我需要的是微信开放平台的 OAuth 认证啊，这两个微信平台的 OAuth 流程是否一致，需要确定下。于是我开始打开了微信开放平台和微信公众平台的 OAuth 流程的文档进行对比，发现果然有些细节处不一致，比如第一步请求 code 时，两者请求地址的形式略有不同，微信开放平台的请求 code 地址是：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://open.weixin.qq.com/connect/qrconnect?appid=APPID&amp;amp;redirect_uri=REDIRECT_URI&amp;amp;response_type=code&amp;amp;scope=SCOPE&amp;amp;state=STATE#wechat_redirect
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而微信公众平台的请求 code 地址却是：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&amp;amp;redirect_uri=REDIRECT_URI&amp;amp;response_type=code&amp;amp;scope=SCOPE&amp;amp;state=STATE#wechat_redirect
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我去查看了 omniauth-wechat-oauth2 的 strategy 源码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# /lib/omniauth/strategies/wechat.rb&lt;/span&gt;
&lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="ss"&gt;:client_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;site:          &lt;/span&gt;&lt;span class="s2"&gt;"https://api.weixin.qq.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;authorize_url: &lt;/span&gt;&lt;span class="s2"&gt;"https://open.weixin.qq.com/connect/oauth2/authorize#wechat_redirect"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;token_url:     &lt;/span&gt;&lt;span class="s2"&gt;"/sns/oauth2/access_token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;token_method:  :get&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个 authorize_url 的地址显然是微信公众平台请求 code 时的格式，这就意味着这个 gem 并不是我需要的。&lt;/p&gt;

&lt;p&gt;不过我发现微信公众平台和微信开放平台的基本 OAuth 流程是类似的，于是我参考 omniauth-wechat-oauth2 的源码，自己实现了微信开放平台的 omniauth strategy，并托管在了&lt;a href="https://github.com/yangsr/omniauth-wechat-oauth2" rel="nofollow" target="_blank" title=""&gt;GitHub 上&lt;/a&gt;。这里感谢一下 omniauth-wechat-oauth2 的原作者 skinnyworm，复用了大部分他的代码。&lt;/p&gt;
&lt;h3 id="CSRF错误"&gt;CSRF 错误&lt;/h3&gt;
&lt;p&gt;剩下的工作就和其他平台的 OAuth 流程差不多了，这里就不再赘述，具体可以看一下文章后的参考链接。&lt;/p&gt;

&lt;p&gt;只是这里遇到了一个 CSRF 错误，特别提一下：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Started GET "/auth/wechat/callback?code=xxxxxxxx&amp;amp;state=xxxxxxxx" for 183.157.160.37 at 2015-04-28 22:26:48 +0800
I, [2015-04-28T22:26:48.017297 #18928]  INFO -- omniauth: (wechat) Callback phase initiated.
E, [2015-04-28T22:26:48.017785 #18928] ERROR -- omniauth: (wechat) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
E, [2015-04-28T22:26:48.017891 #18928] ERROR -- omniauth: (wechat) Authentication failure! invalid_credentials: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是因为我本地调试时习惯性地打开了 localhost:3000，而我又开启了 ngrok，调试时应该直接打开 example.ngrok.io 的。&lt;/p&gt;
&lt;h3 id="参考"&gt;参考&lt;/h3&gt;
&lt;p&gt;railscasts-china 的&lt;a href="http://railscasts-china.com/episodes/omniauth-1" rel="nofollow" target="_blank" title=""&gt;Omniauth 1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;happypeter 的&lt;a href="http://haoduoshipin.com/episodes/98" rel="nofollow" target="_blank" title=""&gt;login-with-linkedin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;感兴趣的同学还可以拓展阅读下&lt;a href="http://www.zhihu.com/question/21074751" rel="nofollow" target="_blank" title=""&gt;微信开放平台和微信公众平台的区别&lt;/a&gt;&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Sun, 03 May 2015 16:13:57 +0800</pubDate>
      <link>https://ruby-china.org/topics/25410</link>
      <guid>https://ruby-china.org/topics/25410</guid>
    </item>
    <item>
      <title>Ruby 整理 hash</title>
      <description>&lt;p&gt;Hi 大家好，我有这么一组 hash：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"2014-11-22"&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="s2"&gt;"2014-11-30"&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="s2"&gt;"2015-01-02"&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="s2"&gt;"2015-01-22"&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;希望能够按月整理成以下这样，遇到相同的月将 hash 的值相加：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"2014-11"&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;"2015-01"&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;该如何实现呢？...&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Wed, 18 Mar 2015 19:51:55 +0800</pubDate>
      <link>https://ruby-china.org/topics/24709</link>
      <guid>https://ruby-china.org/topics/24709</guid>
    </item>
    <item>
      <title>Rails 的 migration 更改</title>
      <description>&lt;p&gt;Hi All.
我的项目现在还处在开发阶段.
之前已经通过 migration 创建了我的数据库。现在想修改一下我的数据库表结构。具体只想修改一个字段
把&lt;code&gt;t.datetime :start_at&lt;/code&gt; 变成 &lt;code&gt;t.date :start_at&lt;/code&gt; 
我可不可以直接修改已有的 migration 文件呢？难道一定要新增一个 migration 文件么？&lt;/p&gt;

&lt;p&gt;我现在把已有的 migration 文件改了，然后在数据库里把原表删除，再执行&lt;code&gt;rake db:migrate&lt;/code&gt; 或者&lt;code&gt;rake db:migrate VERSION=序列号&lt;/code&gt;,发现数据库还是没有创建出那个表。&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Wed, 19 Nov 2014 17:08:03 +0800</pubDate>
      <link>https://ruby-china.org/topics/22764</link>
      <guid>https://ruby-china.org/topics/22764</guid>
    </item>
    <item>
      <title>Rails 中引入 Bootstrap 的问题</title>
      <description>&lt;p&gt;Hi 刚接触 Rails 我想在 Rails 中使用 Bootstrap,.
搜索了下，有的说直接把 Bootstrap 的 js 和 css 导入 vendor 目录就可以了。比如这篇教程：&lt;a href="http://rvg.me/2013/11/using-bootstrap-3-with-rails-4/" rel="nofollow" target="_blank"&gt;http://rvg.me/2013/11/using-bootstrap-3-with-rails-4/&lt;/a&gt;
也有的说导入一些 Gem 包：比如这个：&lt;a href="https://github.com/twbs/bootstrap-sass" rel="nofollow" target="_blank"&gt;https://github.com/twbs/bootstrap-sass&lt;/a&gt;
我想问一下这两种方法有什么区别，哪种更好一些呢？&lt;/p&gt;

&lt;p&gt;另外，如果我想换一下 Bootstrap 导航栏的颜色，想换成蓝色，该怎么做呢？&lt;/p&gt;</description>
      <author>night_7th</author>
      <pubDate>Mon, 20 Oct 2014 11:36:32 +0800</pubDate>
      <link>https://ruby-china.org/topics/22131</link>
      <guid>https://ruby-china.org/topics/22131</guid>
    </item>
  </channel>
</rss>
