<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>so_zengtao (我天真无邪)</title>
    <link>https://ruby-china.org/so_zengtao</link>
    <description>天南地北 随遇而安</description>
    <language>en-us</language>
    <item>
      <title>RabbitMQ Ruby 客户端 Bunny 部分源码解读 </title>
      <description>&lt;p&gt;Debug 的时候顺便看了一下源码、就按照自己的思维对源码有个复盘 &lt;br&gt;
这里记录一下也是顺便安利一下我们项目组在项目中对于某个逻辑常见的复盘方法&lt;br&gt;
ConsumerWorkPool 拉出来是想给大家分享一下 Bunny 制作 Pool 的一个思路、我们的一些逻辑也借用了这个思路&lt;br&gt;
然后总的来说 Bunny 的源码对 面向对象的封装也有很多取舍、代码也谈不上特别漂亮的 (一些方法太长没拆分之类的)&lt;/p&gt;

&lt;p&gt;下面三部分一起介绍了 Queue Subscribe &amp;amp; Consume 的流程&lt;/p&gt;

&lt;hr&gt;
&lt;h4 id="从 ConsumerWorkPool 开始说起 （交代背景 :wink: ）"&gt;从 &lt;a href="https://github.com/ruby-amqp/bunny/blob/master/lib/bunny/consumer_work_pool.rb" rel="nofollow" target="_blank" title=""&gt;ConsumerWorkPool&lt;/a&gt; 开始说起（交代背景 &lt;img title=":wink:" alt="😉" src="https://twemoji.ruby-china.com/2/svg/1f609.svg" class="twemoji"&gt; ）&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;ConsumerWorkPool&lt;/code&gt; 顾名思义也就是 &lt;code&gt;消费者工作的池子&lt;/code&gt; &lt;br&gt;
&lt;code&gt;ConsumerWorkPool&lt;/code&gt; 通过 &lt;code&gt;死循环&lt;/code&gt; 利用 线程 (Thread) 去 &lt;code&gt;消费(consume) 队列中生产者积攒的消息&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;三个比较重要的 Instance Method&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="ss"&gt;submit: &lt;/span&gt;&lt;span class="n"&gt;整个池子动起来之后唯一能被外界塞入待处理消息的地方&lt;/span&gt;
&lt;span class="ss"&gt;start:  &lt;/span&gt;&lt;span class="n"&gt;初始化整个池子的运转&lt;/span&gt; &lt;span class="n"&gt;可以看到创建线程&lt;/span&gt; &lt;span class="n"&gt;并且准备好了循环体&lt;/span&gt;    
&lt;span class="ss"&gt;join:   &lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConsumerWorkPool&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:threads&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:size&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="vi"&gt;@queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# submit 方法可以说是这个工作池启动工作的外界因素了 （顺便，&amp;amp;block 本来就是 callable 的）&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@queue.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callable&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;block&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;start&lt;/span&gt;
    &lt;span class="vi"&gt;@threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="vi"&gt;@size.times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&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;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:run_loop&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;               
      &lt;span class="vi"&gt;@threads&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="vi"&gt;@running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&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;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@threads&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;t&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;timeout&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="kp"&gt;protected&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_loop&lt;/span&gt;
      &lt;span class="kp"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:terminate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@paused&lt;/span&gt;      
          &lt;span class="n"&gt;callable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@queue.pop&lt;/span&gt;

          &lt;span class="k"&gt;begin&lt;/span&gt;
            &lt;span class="n"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
          &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;StandardError&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="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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h4 id="然后就是 Queue 和 Consumer"&gt;然后就是 &lt;a href="https://github.com/ruby-amqp/bunny/blob/master/lib/bunny/queue.rb" rel="nofollow" target="_blank" title=""&gt;Queue&lt;/a&gt; 和 &lt;a href="https://github.com/ruby-amqp/bunny/blob/master/lib/bunny/consumer.rb" rel="nofollow" target="_blank" title=""&gt;Consumer&lt;/a&gt;
&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Queues store and forward messages to consumers.&lt;/li&gt;
&lt;li&gt;Messages flow from producer to exchanges that route them to queues &amp;amp; queues deliver the message to consumer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;队列的概念存在于消费者这边。消费者的客户端需要去订阅队列，例如官方案例：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;block: &lt;/span&gt;&lt;span class="kp"&gt;true&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;_delivery_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_properties&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="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;" [x] Received &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;body&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;可以看到 &lt;code&gt;subscribe&lt;/code&gt; 方法创建了一个 &lt;code&gt;Comsumer&lt;/code&gt; 的实例 &lt;br&gt;&lt;/p&gt;

&lt;p&gt;然后将业务逻辑的代码块 - 也就是 &amp;amp;block（顺便也是上文提到的 callable）作为参数传给 &lt;code&gt;Comsumer#on_delivery&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;等待 &lt;code&gt;consumer&lt;/code&gt; 被上文提到的 &lt;code&gt;ConsumerWorkPool&lt;/code&gt; &lt;code&gt;call&lt;/code&gt; ( 也就是执行业务逻辑) 即可&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;
  &lt;span class="c1"&gt;# Adds a consumer to the queue&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Comsumer&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="vi"&gt;@channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on_delivery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@channel.basic_consume_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumer&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;opts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:block&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@channel.work_pool.join&lt;/span&gt;           &lt;span class="c1"&gt;# 这里是直接启动线程了&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;consumer&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;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Consumer&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_delivery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@on_delivery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;
    &lt;span class="nb"&gt;self&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@on_delivery.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@on_delivery&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;handle_delivery&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="继续往下我们可以看到 Channel"&gt;继续往下我们可以看到 &lt;a href="https://github.com/ruby-amqp/bunny/blob/master/lib/bunny/channel.rb" rel="nofollow" target="_blank" title=""&gt;Channel&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;Channel 可以说是 RabbitMQ 交互的核心、因为 Connection 的建立、销毁代价太高，使用了 Channel 来多路复用一个 TCP 连接&lt;/p&gt;

&lt;p&gt;在这里我们关心以下几个方法&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;basic_consume_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="no"&gt;Register&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="no"&gt;Consumer&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; 
&lt;span class="n"&gt;maybe_start_consumer_work_pool!&lt;/span&gt;  &lt;span class="n"&gt;保证启动&lt;/span&gt; &lt;span class="n"&gt;consumer_work_pool&lt;/span&gt;
&lt;span class="n"&gt;register_consumer&lt;/span&gt;
&lt;span class="n"&gt;handle_frameset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basic_deliver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Channel&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;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;work_pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConsumerWorkPool&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="vi"&gt;@consumers&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&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;basic_consume_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;maybe_start_consumer_work_pool!&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;register_consumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;consumer_tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer&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;maybe_start_consumer_work_pool!&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@work_pool&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="vi"&gt;@work_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;running?&lt;/span&gt;
      &lt;span class="vi"&gt;@work_pool.start&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;generate_consumer_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bunny"&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="nb"&gt;name&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="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_i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&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="no"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;999_999_999_999&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="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register_consumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumer_tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@consumer_mutex.synchronize&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@consumers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;consumer_tag&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumer&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;# 可以看到这里调用了 ConsumerWorkPool 的 submit 方法、 consumer 自己也 call 了&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_frameset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basic_deliver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@consumers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;basic_deliver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;consumer_tag&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;consumer&lt;/span&gt;
      &lt;span class="vi"&gt;@work_pool.submit&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;begin&lt;/span&gt;
          &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DeliveryInfo&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;basic_deliver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;MessageProperties&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;properties&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&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="vi"&gt;@uncaught_exception_handler&lt;/span&gt;&lt;span class="p"&gt;.&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;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@uncaught_exception_handler&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;else&lt;/span&gt;
      &lt;span class="vi"&gt;@logger.warn&lt;/span&gt; &lt;span class="s2"&gt;"No consumer for tag &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;basic_deliver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;consumer_tag&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; on channel &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@id&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;/code&gt;&lt;/pre&gt;</description>
      <author>so_zengtao</author>
      <pubDate>Fri, 03 Aug 2018 16:16:28 +0800</pubDate>
      <link>https://ruby-china.org/topics/37277</link>
      <guid>https://ruby-china.org/topics/37277</guid>
    </item>
    <item>
      <title>[武汉] 天融信 招聘中高级 Ruby 工程师 ～ 想回武汉的小伙伴们来吧</title>
      <description>&lt;h3 id="公司背景介绍"&gt;公司背景介绍&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://www.topsec.com.cn/" rel="nofollow" target="_blank" title=""&gt;天融信&lt;/a&gt;是中国领先的信息安全产品与服务解决方案提供商。基于创新的“可信网络架构”以及业界领先的信息安全产品与服务，天融信致力于改善用户网络与应用的可视性、可用性、可控性和安全性，降低安全风险，创造业务价值。&lt;/p&gt;
&lt;h3 id="招聘的岗位"&gt;招聘的岗位&lt;/h3&gt;&lt;h4 id="Ruby 开发工程师"&gt;Ruby 开发工程师&lt;/h4&gt;&lt;h5 id="岗位职责："&gt;岗位职责：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;参与项目需求分析、业务逻辑流程设计、文档编写；&lt;/li&gt;
&lt;li&gt;负责主要程序代码编写；&lt;/li&gt;
&lt;li&gt;协助对所开发的功能进行测试，协助产品部署；&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id="任职资格："&gt;任职资格：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;2 年以上 Ruby on Rails 开发经验；&lt;/li&gt;
&lt;li&gt;能在 Linux（Debian 或 Ubuntu）系统下进行独立工作；&lt;/li&gt;
&lt;li&gt;熟练使用 Ruby 语言及 Rails 框架；&lt;/li&gt;
&lt;li&gt;熟悉 HTML5、Jquery, Boostrap 等前端开发技术； &lt;/li&gt;
&lt;li&gt;使用过 watir、selenium、webdriver 者优先；&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="一些你可能想知道的"&gt;一些你可能想知道的&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;全额缴纳五险一金&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;公积金公司缴纳比例高达 12%&lt;/li&gt;
&lt;li&gt;国家法定节假日休息、不占用私人周末&lt;/li&gt;
&lt;li&gt;9 - 16k 的薪资空间（超预期的牛人可以另谈）&lt;/li&gt;
&lt;li&gt;其它暂时没想好。该有的都有&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;我们在&lt;strong&gt;光谷创业街&lt;/strong&gt;这边
最后有意向的同学请联系这里：&lt;a href="mailto:liu_desen@topsec.com.cn" title=""&gt;liu_desen@topsec.com.cn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;依旧没有特别华丽的词藻。欢迎踏实、实在的朋友来共事&lt;/p&gt;</description>
      <author>so_zengtao</author>
      <pubDate>Fri, 01 Jun 2018 21:23:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/36879</link>
      <guid>https://ruby-china.org/topics/36879</guid>
    </item>
    <item>
      <title>[杭州] 浮冬数据 - 暂时停止招聘</title>
      <description>&lt;h3 id="版本 1.1 更新注记"&gt;版本 1.1 更新注记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;我们已经入职了一位后端工程师、现在还需要一位后端工程师（Node 尤佳）&lt;/li&gt;
&lt;li&gt;更新了福利模块 -【增加】5、6 两项&lt;/li&gt;
&lt;li&gt;我们希望候选者有 &lt;strong&gt;很强的执行力&lt;/strong&gt; 和 &lt;strong&gt;工程素养&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="关于我们"&gt;关于我们&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.risewinter.com" rel="nofollow" target="_blank" title=""&gt;浮冬数据&lt;/a&gt; 又开始招聘新的伙伴了&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;一家于 2016 年 6 月成立于新加坡的 &lt;strong&gt;电竞数据服务&lt;/strong&gt; &lt;strong&gt;创业公司&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;拿到了千万级别的 PreA 轮融资&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruby-china.org/topics/31831" title=""&gt;传送门 - 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;现因为业务发展的需要现在有 &lt;del&gt;两个&lt;/del&gt; 一个 &lt;strong&gt;全栈&lt;/strong&gt; 的职位 和 一个 &lt;strong&gt;运维&lt;/strong&gt; 的职位&lt;/p&gt;
&lt;h2 id="福利"&gt;福利&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt; 入职一年即可享受每年长达 &lt;strong&gt;十&lt;/strong&gt; 天的年假&lt;/li&gt;
&lt;li&gt; 相对来说高于行业平均线的工资水平「&lt;strong&gt;15K - 25K&lt;/strong&gt;」&lt;/li&gt;
&lt;li&gt; 共享公司高速发展带来的成果「我们&lt;strong&gt;部门有独立的期权池&lt;/strong&gt;」&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;公司拥有海量的数据供你挖掘和处理&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;每个月&lt;/strong&gt;有相应的项目考核奖金 - 额度也 &lt;strong&gt;比较给力&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;每人每年最少有 4 次&lt;/strong&gt; 调薪机会 - 幅度也 &lt;strong&gt;非常给力&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="岗位"&gt;岗位&lt;/h2&gt;&lt;h4 id="Base 要求"&gt;Base 要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt; 拥有写清晰文档（注释是文档的子集）的能力&lt;/li&gt;
&lt;li&gt; 拥有独立完成产品功能开发的能力&lt;/li&gt;
&lt;li&gt; 拥有设计并部署分布式应用、以及协调各服务之间远程调用的能力&lt;/li&gt;
&lt;li&gt; 代码结构规范、逻辑清晰合理&lt;/li&gt;
&lt;li&gt; 熟悉 表现层状态转化 规范、理解 Resource 和 MVC&lt;/li&gt;
&lt;li&gt; 对身边的人和事负责、愿意花时间去沟通并解决问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="Ruby 工程师"&gt;Ruby 工程师&lt;/h3&gt;&lt;h4 id="职责"&gt;职责&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt; 开发公司内部数据接口并打通与公司其它现有平台的数据通道&lt;/li&gt;
&lt;li&gt; 负责公司新平台的所有研发工作&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="要求"&gt;要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt; 精通 RoR 开发 &amp;amp; APi（指代这个&lt;a href="http://api.rubyonrails.org" rel="nofollow" target="_blank" title=""&gt;APi&lt;/a&gt;） - 工作年限不限定&lt;/li&gt;
&lt;li&gt; 熟悉关系型数据库 &amp;amp; Redis&lt;/li&gt;
&lt;li&gt; 熟悉 Linux、Git、Nginx&lt;/li&gt;
&lt;li&gt; 能实现较复杂的前端开发、独立完成 HTML、CSS、JavaScript 的工作，熟悉 WebPack Vue React 等尤佳&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="Node 工程师"&gt;Node 工程师&lt;/h3&gt;&lt;h4 id="职责"&gt;职责&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt; 开发公司内部数据接口并打通与部分外部平台的数据通道&lt;/li&gt;
&lt;li&gt; 负责公司新平台的所有研发工作&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="要求"&gt;要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt; 对 HTTP，TCP 等基础协议有一定了解和应用&lt;/li&gt;
&lt;li&gt; 拥有扎实的 NodeJS 后端功底 (Http、SocketIo、Mysql、Redis、Hbase 等)&lt;/li&gt;
&lt;li&gt; 拥有扎实的 前端 功底 (闭包、事件、异步、CSS 等)&lt;/li&gt;
&lt;li&gt; 拥有连续重构系统的能力&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="最后的个人的一些补充"&gt;最后的个人的一些补充&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;我们是一家创业公司，和其它公司不一样的是我们 &lt;strong&gt;没有&lt;/strong&gt; 什么不打卡、弹性工作时间这样 &lt;code&gt;人性化&lt;/code&gt; 地规定&lt;/li&gt;
&lt;li&gt;我们愿意为你的额外 &lt;strong&gt;有效劳动&lt;/strong&gt; 付出一定量的报酬&lt;/li&gt;
&lt;li&gt;希望每一个愿意过来的人都能得到自己想要的东西，不管是物质上的回报、技能上的成长还是其它不能量化的东西&lt;/li&gt;
&lt;li&gt;我们愿意分享创业的成果，所以不希望过来的人在我们这里浪费了青春、蹉跎了岁月、荒废了彼此 - 也就是说 &lt;strong&gt;我们不欢迎混的人&lt;/strong&gt; 。青春可贵、这也是我这几年深刻的体会&lt;/li&gt;
&lt;li&gt;这是一份没有华丽词藻的 JD，该有的福利都会有，双 Dell 24 都不叫事&lt;/li&gt;
&lt;li&gt;最大的加分点 是 你是一个靠谱的人&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;如果你好学、踏实那么即使 不那么满足上述要求也不要紧&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;如果上述要求除了薪资之外你都满足、那么你可以提出你的要求&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="工作地点 &amp;amp; 联系方式"&gt;工作地点 &amp;amp; 联系方式&lt;/h3&gt;
&lt;p&gt;部门这边可以自主招聘&lt;/p&gt;

&lt;p&gt;杭州市滨江区滨盛路 1509 号天恒大厦&lt;/p&gt;

&lt;p&gt;有意者请将简历发送至： &lt;a href="mailto:%20zengtao@risewinter.com" title=""&gt;zengtao@risewinter.com&lt;/a&gt;&lt;/p&gt;</description>
      <author>so_zengtao</author>
      <pubDate>Sat, 11 Nov 2017 12:10:55 +0800</pubDate>
      <link>https://ruby-china.org/topics/34556</link>
      <guid>https://ruby-china.org/topics/34556</guid>
    </item>
    <item>
      <title>【提供了一般的解决方案看看有没有更好的 顺便 5 楼新问题】多态下的查询（不知道怎么用术语）看到的小伙伴进来看看吧</title>
      <description>&lt;p&gt;老习惯先贴代码吧
先看 模型&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Collocation 和 Group 都有 state 和 feature 属性&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Collocation&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt;   &lt;span class="ss"&gt;:hit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="ss"&gt;as: :hitable&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt;  &lt;span class="ss"&gt;:sets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="ss"&gt;as: :setable&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Group&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt;   &lt;span class="ss"&gt;:hit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="ss"&gt;as: :hitable&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt;  &lt;span class="ss"&gt;:sets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="ss"&gt;as: :setable&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt;  &lt;span class="ss"&gt;:setable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="ss"&gt;:polymorphic&lt;/span&gt;
  &lt;span class="c1"&gt;# 我想在下面这个scope里面 取到对应的state 和 feature 的 Collocation 和 Group 怎么写&lt;/span&gt;
  &lt;span class="c1"&gt;# 下面的这个写法不对&lt;/span&gt;
  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:active_sets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:setable&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;setable: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;state: &lt;/span&gt;&lt;span class="s1"&gt;'ACTIVE'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;feature: &lt;/span&gt;&lt;span class="kp"&gt;true&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后看看我在 Controller 里面原来的比较搓的方法&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="vi"&gt;@sets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
  &lt;span class="vi"&gt;@sets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&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;set&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"ACTIVE"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_featured&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;这样是可以的&lt;/span&gt; &lt;span class="n"&gt;但是现在想&lt;/span&gt; &lt;span class="n"&gt;这样写&lt;/span&gt;

&lt;span class="vi"&gt;@sets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_sets&lt;/span&gt; &lt;span class="c1"&gt;# 这里就是上面模型里面我不知道该怎么写的 诸位大侠。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我理解的多态 是一个 容器（也是 C++ 里面的基类）用基类指针数组去找子类特定的属性。。反正好吧就是这样的 有没有小伙伴告诉我这个怎么写 某再次多谢了&lt;/p&gt;</description>
      <author>so_zengtao</author>
      <pubDate>Mon, 15 Sep 2014 16:33:59 +0800</pubDate>
      <link>https://ruby-china.org/topics/21537</link>
      <guid>https://ruby-china.org/topics/21537</guid>
    </item>
    <item>
      <title>诸位看看我这样理解 rails 的用户登陆过程是不是正确的</title>
      <description>&lt;p&gt;所谓的用户登陆&lt;/p&gt;

&lt;p&gt;其实就是在网站的每个页面（也就是 每个控制器 的 每个动作 都能取到 current_user）&lt;/p&gt;

&lt;p&gt;然后在浏览器里的 cookies 里面存储的是一个没有加密的 hash_string1&lt;/p&gt;

&lt;p&gt;然后在数据库里面存储一个加密的 hash_string2 (加密 hash_string1)&lt;/p&gt;

&lt;p&gt;然后每个页面通过 cookies 拿到 hash_string1  然后加密之后找到 user 这个找到的 user 就是 current_user&lt;/p&gt;

&lt;p&gt;然后就可以对这个 current_user 进行各种蹂躏了对么 亲们？&lt;/p&gt;</description>
      <author>so_zengtao</author>
      <pubDate>Tue, 27 May 2014 16:26:43 +0800</pubDate>
      <link>https://ruby-china.org/topics/19567</link>
      <guid>https://ruby-china.org/topics/19567</guid>
    </item>
    <item>
      <title>在 Carrierwave 的 Git 上看到一段卖萌的代码</title>
      <description>&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_human?&lt;/span&gt; &lt;span class="n"&gt;picture&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;can_program?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ruby&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;</description>
      <author>so_zengtao</author>
      <pubDate>Wed, 21 May 2014 15:49:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/19449</link>
      <guid>https://ruby-china.org/topics/19449</guid>
    </item>
    <item>
      <title>问一个 ruby 模型中关系数据库的问题。</title>
      <description>&lt;p&gt;1：表 products 有属性：product_detail_id 和 product_type_id
也就是说每个产品都有一个 产品详情 和一个 产品种类&lt;/p&gt;

&lt;p&gt;（所以还有表格 ProductDetails 和 ProductTypes）
2：看模型的定义：&lt;/p&gt;

&lt;p&gt;下面代码是说 一个 product 实例有一个 (成员变量 C++ 的说法)product_type 类型是 ProductType 通过 :product_type_id 这个值在 ProductTypes 这个表中唯一确定取回该值赋给 product_type
(如果理解错了 还望诸位指正)&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;Product&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:product_type_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:product_detail_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;

  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:product_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;foreign_key: :product_type_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class_name: &lt;/span&gt;&lt;span class="s2"&gt;"ProductType"&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:product_detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;foreign_key: :product_detail_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class_name: &lt;/span&gt;&lt;span class="s2"&gt;"ProductDetail"&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我在 ProductType 的模型里面直接这么写不知道可不可以？（可以的话能告诉我为什么嘛？我这里就在 activeadmin 这个 gem 里注册的时候出错了。（是不是要在 ProductTypes 的数据库中加入 product_id 这个列才行？为什么？）&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;ProductType&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;  
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:product&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;</description>
      <author>so_zengtao</author>
      <pubDate>Mon, 19 May 2014 14:38:25 +0800</pubDate>
      <link>https://ruby-china.org/topics/19377</link>
      <guid>https://ruby-china.org/topics/19377</guid>
    </item>
    <item>
      <title>一个 Ajax 的问题 新手 网上都说的比较含糊所以来详细的问问。</title>
      <description>&lt;p&gt;1：先看路由吧：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s2"&gt;"/update_rooms"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"admin/lessons#update_rooms"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2：然后看看视图：&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;Venue &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;select_tag&lt;/span&gt; &lt;span class="s2"&gt;"venue_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options_for_select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@venues.map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&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="p"&gt;}),&lt;/span&gt; 
    &lt;span class="ss"&gt;:prompt&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Please select project"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="ss"&gt;:onchange&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"update_versions_div(this.value)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:remote&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;  &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"roomsByVenue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:partial&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'roomsbyvenue'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:locals&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面是_roomsbyvenue.html.erb&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;Room&lt;span class="cp"&gt;&amp;lt;%=&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;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:room_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options_for_select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@rooms.map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&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="p"&gt;}))&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/br&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：js 的代码&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;update_versions_div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;venue_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;jQuery&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="s2"&gt;/update_rooms&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="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;venue_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;venue_id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;datatype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="na"&gt;success&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;data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="nf"&gt;jQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#roomsByVenue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好了 问题来了。首先 在 application.html.erb 里面是可以知道任何在 assert/javascripts 里面的文件最后都是会被包含进来的。好了 我现在直接在 application.js 的最后加上了上述的 js 代码。然后到视图去操作 然后浏览器的调试会显示
见下图
&lt;img src="//l.ruby-china.com/photo/2014/58253ac5c1368a4d2cb8dea23b328c5d.png" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>so_zengtao</author>
      <pubDate>Thu, 15 May 2014 09:42:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/19266</link>
      <guid>https://ruby-china.org/topics/19266</guid>
    </item>
  </channel>
</rss>
