<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>breeze (breeze🐑)</title>
    <link>https://ruby-china.org/breeze</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>关于数据库部份表做中英版本的探讨</title>
      <description>&lt;h2 id="欢迎大家来指出不好的地方"&gt;欢迎大家来指出不好的地方&lt;/h2&gt;&lt;h3 id="产品需求分析"&gt;产品需求分析&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;用户账号体系不分中英文版本：在中文版本下注册的用户，在英文版本中也可以登录。&lt;/li&gt;
&lt;li&gt;资讯类的数据做中英文两个版本：在中文版本中只有中文资讯，英文版本下只有英文资讯。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="解决思路"&gt;解决思路&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;一个数据库，用户表不分中英两张表。资讯类的表分中英两张表。&lt;/li&gt;
&lt;li&gt;部署两个 rails 服务 (中英各一个)，在 initialization 中使 model table_name 映射到相应版本的表名。&lt;/li&gt;
&lt;li&gt;通过 Nginx 根据自定义的 http 头识别中英版本的请求，转发到相应的 rails 服务。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="具体代码"&gt;具体代码&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;例如创建两个版本的帖子表：cn_topics 与 en_topics&lt;/li&gt;
&lt;li&gt;创建一个名为 Topic 的 Model&lt;/li&gt;
&lt;li&gt;在 config/initializers 中 创建 map_multiversion_models.rb&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;MULTIVERSION_MODELS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w(Topic)&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'CURRENT_LANG'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'CN'&lt;/span&gt;
  &lt;span class="n"&gt;current_lang_prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'cn'&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="n"&gt;current_lang_prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'en'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;MULTIVERSION_MODELS&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;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;safe_constantize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table_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;current_lang_prefix&lt;/span&gt;&lt;span class="si"&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;underscore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pluralize&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;ol&gt;
&lt;li&gt;nginx 的转发配置&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;upstream&lt;/span&gt; &lt;span class="n"&gt;cn_production&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="mf"&gt;192.168&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;upstream&lt;/span&gt; &lt;span class="n"&gt;en_production&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="mf"&gt;192.168&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;location&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="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$http_x_current_lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'cn'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="ss"&gt;:/&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cn_production&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$http_x_current_lang&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;'cn'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="ss"&gt;:/&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;en_production&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="方案分析"&gt;方案分析&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;数据隔离上通常有三种做法：数据库隔离、表隔离、元数据隔离。

&lt;ul&gt;
&lt;li&gt;数据库实例隔离不符合业务需求&lt;/li&gt;
&lt;li&gt;元数据隔离方案会对正常业务代码造成污染，增加 lang 的字段来区别。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; 采用表隔离的方式，并用上面的解决方案

&lt;ul&gt;
&lt;li&gt;可以按正常的逻辑去写业务代码，避免了因为中英文版本问题对代码做兼容处理。&lt;/li&gt;
&lt;li&gt;只需在环境变量中指定当前语言版本，即可同一套测试代码测试指定语言版本的业务代码&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>breeze</author>
      <pubDate>Sun, 22 Apr 2018 22:10:35 +0800</pubDate>
      <link>https://ruby-china.org/topics/35508</link>
      <guid>https://ruby-china.org/topics/35508</guid>
    </item>
    <item>
      <title>Puma 的线程数量与数据库连接池的关系</title>
      <description>&lt;h3 id="puma是rails5的标配可是你知道 puma的线程数与数据库连接池的关系吗？"&gt;puma 是 rails5 的标配可是你知道 puma 的线程数与数据库连接池的关系吗？&lt;/h3&gt;
&lt;p&gt;当我们配置 rails 的时候应注意 puma 的线程数与数据库连接池数一致。&lt;/p&gt;

&lt;p&gt;否则会出来一些奇怪的现象：&lt;/p&gt;

&lt;p&gt;例如在并发大，但是在内存，cpu,mysql 压力不大的情况下，ruby 耗时特别的长。&lt;a href="https://ruby-china.org/topics/33484#%E5%8E%8B%E6%B5%8B3" title=""&gt;使用 Newrelic 与 ab 工具 尝试了解项目的性能&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;例如得到一个错误：ActiveRecord::ConnectionTimeoutError (could not obtain a connection from the pool within 5.000 seconds (waited 5.002 seconds); all pooled connections were in use)&lt;/p&gt;
&lt;h3 id="下面我们通过 connection_pool的源码来了解一下"&gt;下面我们通过 connection_pool 的源码来了解一下&lt;/h3&gt;
&lt;p&gt;这里有着一个缓存，缓存着一个 conn, 这个 conn，在此次的请求中可以被使用任意次数。缓存不存在时，将从连接池中获取相应的 conn&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#363&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connection&lt;/span&gt;
  &lt;span class="vi"&gt;@thread_cached_conns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;connection_cache_key&lt;/span&gt;&lt;span class="p"&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;current&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;#/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#389&lt;/span&gt;

&lt;span class="c1"&gt;# If all connections are leased and the pool is at capacity (meaning the&lt;/span&gt;
&lt;span class="c1"&gt;# number of currently leased connections is greater than or equal to &lt;/span&gt;
&lt;span class="c1"&gt;# size limit set), an ActiveRecord::ConnectionTimeoutError exception will be raised.&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checkout_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@checkout_timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;checkout_and_verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acquire_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checkout_timeout&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;获取 conn 的方式有以下三种，第一种是直接返回可用的 conn, 我们现在先关注第二种，尝试创建 conn，并控制着进程中所有的线程创建的连接数。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#706&lt;/span&gt;

&lt;span class="c1"&gt;# Acquire a connection by one of 1) immediately removing one&lt;/span&gt;
&lt;span class="c1"&gt;# from the queue of available connections, 2) creating a new&lt;/span&gt;
&lt;span class="c1"&gt;# connection if the pool is not at capacity, 3) waiting on the&lt;/span&gt;
&lt;span class="c1"&gt;# queue for a connection to become available.&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;acquire_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checkout_timeout&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;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@available.poll&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;try_to_checkout_new_connection&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;reap&lt;/span&gt;
    &lt;span class="vi"&gt;@available.poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checkout_timeout&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;#/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#739&lt;/span&gt;

&lt;span class="c1"&gt;# If the pool is not at a +@size+ limit, establish new connection. Connecting&lt;/span&gt;
&lt;span class="c1"&gt;# to the DB is done outside main synchronized section.&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;try_to_checkout_new_connection&lt;/span&gt;
  &lt;span class="c1"&gt;# first in synchronized section check if establishing new conns is allowed&lt;/span&gt;
  &lt;span class="c1"&gt;# and increment @now_connecting, to prevent overstepping this pool's @size&lt;/span&gt;
  &lt;span class="c1"&gt;# constraint&lt;/span&gt;
  &lt;span class="n"&gt;do_checkout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;synchronize&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@threads_blocking_new_connections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@connections.size&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="vi"&gt;@now_connecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="vi"&gt;@size&lt;/span&gt;
      &lt;span class="vi"&gt;@now_connecting&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&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;if&lt;/span&gt; &lt;span class="n"&gt;do_checkout&lt;/span&gt;
    &lt;span class="k"&gt;begin&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;checkout_new_connection&lt;/span&gt;
    &lt;span class="k"&gt;ensure&lt;/span&gt;
      &lt;span class="n"&gt;synchronize&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;
          &lt;span class="n"&gt;adopt_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="c1"&gt;# returned conn needs to be already leased&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;lease&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="vi"&gt;@now_connecting&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&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;当没有可用的 conns，并且也已经达到创建 conn 的上限时，该怎么办呢？这时就会等待使用中的 conns 的释放，等待超时了就会报错&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#147&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;poll&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="n"&gt;synchronize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;internal_poll&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;internal_poll&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="n"&gt;no_wait_poll&lt;/span&gt; &lt;span class="o"&gt;||&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;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;wait_poll&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="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wait_poll&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="vi"&gt;@num_waiting&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

  &lt;span class="n"&gt;t0&lt;/span&gt; &lt;span class="o"&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="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@cond.wait&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="n"&gt;elapsed&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;remove&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;any?&lt;/span&gt;

    &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&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="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use'&lt;/span&gt; &lt;span class="o"&gt;%&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="n"&gt;elapsed&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;ConnectionTimeoutError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&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;ensure&lt;/span&gt;
  &lt;span class="vi"&gt;@num_waiting&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&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;h3 id="总结"&gt;总结&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;当使用多线程的 rails 服务器时，应当注意：连接池的数量与线程数量相同。&lt;/li&gt;
&lt;li&gt;当连接池数小于线程数并且高负载时，某些线程会等待 conn 的释放，而影响访问速度与性能。具体情况可以查看该帖子：&lt;a href="https://ruby-china.org/topics/33484#%E5%8E%8B%E6%B5%8B3" title=""&gt;使用 Newrelic 与 ab 工具 尝试了解项目的性能&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;当偶尔发生 ActiveRecord::ConnectionTimeoutError 错误时，请检查连接池数&lt;/li&gt;
&lt;li&gt;puma 配置中默认线程是 0-16，数据库连接池默认是 5。可能大多人在并发高的时候都需要增加连接池。&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>breeze</author>
      <pubDate>Wed, 07 Mar 2018 23:29:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/35191</link>
      <guid>https://ruby-china.org/topics/35191</guid>
    </item>
    <item>
      <title>使用 Newrelic 与 ab 工具 尝试了解项目的性能</title>
      <description>&lt;h3 id="压测1"&gt;压测 1&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt; 服务器为  8 核 16g，使用 puma 开启 15 个 wokers&lt;/li&gt;
&lt;li&gt; 每秒 200 请求压测 重度使用 mysql 的 api 接口&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="总结："&gt;总结：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;平均每个请求的时间都要 1.6s 以上，apdex 得分非常的低&lt;/li&gt;
&lt;li&gt;ruby 占用时间为 60% 左右，mysql 占了将近 40%。&lt;/li&gt;
&lt;li&gt;尝试通过提升服务器的配置性能到 12 核，puma 开多几个实例。效率还是很低，并没有与提升的配置成正比。
&lt;img src="https://l.ruby-china.com/photo/2017/5c6a6861-f193-4ae4-983b-aae14c11cefc.png!large" title="" alt=""&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="压测2"&gt;压测 2&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt; 在上一个压测中，ruby 占用的时间实在太多了，又没有解决思路，决定转变下压测条件。&lt;/li&gt;
&lt;li&gt; 使用 nginx 做负载均衡，性能好的服务器 weight 为 2，另一个 weight 为 1。&lt;/li&gt;
&lt;li&gt; 每一台服务器为  4 核 8g，使用 puma 开启 8 个 wokers&lt;/li&gt;
&lt;li&gt; 第二台服务器为  2 核 4g，使用 puma 开启 5 个 wokers&lt;/li&gt;
&lt;li&gt; 每秒 200 请求压测 重度使用 mysql 的 api 接口&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="总结："&gt;总结：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;效率明显上升，apdex 得分看起来不错了&lt;img title=":joy:" alt="😂" src="https://twemoji.ruby-china.com/2/svg/1f602.svg" class="twemoji"&gt; &lt;/li&gt;
&lt;li&gt;虽然效率上升了，但是 ruby 占用时间还是很高 (这个需要继续探索)&lt;/li&gt;
&lt;li&gt;在服务器的配置 比 压测 1 的服务器配置差的情况下，既然效率会更高。这是负载均衡的功劳了，成功让对单台服务器的并发降了下来。&lt;/li&gt;
&lt;li&gt;并发越高，服务器性能越差 (参考下面第二张图)。
&lt;img src="https://l.ruby-china.com/photo/2017/d236d1de-f2f3-42d9-8fe3-3ee9aea8bdea.png!large" title="" alt=""&gt;
* * *
&lt;img src="https://l.ruby-china.com/photo/2017/2e0e2263-678f-4823-a686-a18aa34ca014.png!large" title="" alt=""&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="压测3"&gt;压测 3&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt; 分析代码后，代码并没有可疑之处。可是为什么 ruby 占用时间那么高呢？&lt;/li&gt;
&lt;li&gt;怀疑是在什么地方排队等候，花了时间。&lt;/li&gt;
&lt;li&gt;在等 mysql？redis?&lt;/li&gt;
&lt;li&gt;rails 中 mysql 默认连接池为 5，尝试压测不同数据的连接池。&lt;/li&gt;
&lt;li&gt;为减少影响，使用单台服务器 服务器为  4 核 8g，使用 puma 开启 8 个 wokers&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="总结："&gt;总结：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;5pool 的条件下：ruby 花费了 60% 的时间。&lt;/li&gt;
&lt;li&gt;提升了 pool 之后：ruby 花费的时间降下来了，花了 20% 左右。&lt;/li&gt;
&lt;li&gt;原来 ruby 花费了大部分的时间，是在等待 mysql 的连接池啊。&lt;/li&gt;
&lt;li&gt;现在是 mysql 占用大部分的时间了，可以专心的优化 sql 之类的了&lt;img title=":muscle:" alt="💪" src="https://twemoji.ruby-china.com/2/svg/1f4aa.svg" class="twemoji"&gt; 
&lt;img src="https://l.ruby-china.com/photo/2017/38d201f7-a60a-4c45-9d20-4eed4f38211a.png!large" title="" alt=""&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="追加"&gt;追加&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;之后尝试使用 gem 'connection_pool' 为 redis_store 增加了连接池，增加后没有什么变化。&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>breeze</author>
      <pubDate>Thu, 13 Jul 2017 12:44:06 +0800</pubDate>
      <link>https://ruby-china.org/topics/33484</link>
      <guid>https://ruby-china.org/topics/33484</guid>
    </item>
    <item>
      <title>求解 singleton_class, singleton_methods 的深入问题</title>
      <description>&lt;h3 id="环境： ruby2.3.2"&gt;环境：ruby2.3.2&lt;/h3&gt;&lt;h5 id="问题："&gt;问题：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;为什么下面两者的 ancestors 差这么多，A 与 A.singleton_class 有哪些关联与不同？&lt;/li&gt;
&lt;li&gt;与 A.ancestors 相比 A.singleton_class.ancestors 中 #&amp;lt;Class:A&amp;gt;, #&amp;lt;Class:Object&amp;gt;类似这些东西是什么？&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ancestors&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; [A, Object, Kernel, BasicObject]&lt;/span&gt;

&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ancestors&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; [#&amp;lt;Class:A&amp;gt;, #&amp;lt;Class:Object&amp;gt;, #&amp;lt;Class:BasicObject&amp;gt;, Class, Module, Object, Kernel, BasicObject] &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="问题："&gt;问题：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;为什么不是一个 singleton_class 也可以定义 singleton_method ?&lt;/li&gt;
&lt;li&gt;现在可以推出，A 与 A.singleton_class 是完全不同的东西，那么 A.singleton_class 存在的意义是什么？&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&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;say&lt;/span&gt;
    &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s1"&gt;'say'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_methods&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; [:say]&lt;/span&gt;

&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_methods&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; [:constants, :nesting]   方法中没有:say,这个可以理解，因为它的ancestors中没有A。&lt;/span&gt;

&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class?&lt;/span&gt;
&lt;span class="c1"&gt;#  =&amp;gt; false&lt;/span&gt;

&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class?&lt;/span&gt;
&lt;span class="c1"&gt;#  =&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="问题："&gt;问题：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;如果说 A.say 是一个 singleton_method，也是一个类方法，那么 a1.run 是一个 singleton_method，也是一个类方法？&lt;/li&gt;
&lt;li&gt;类方法与 singleton_method 有什么关系与不同？&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&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;say&lt;/span&gt;
    &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s1"&gt;'say'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_methods&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; [:say]&lt;/span&gt;

&lt;span class="n"&gt;a1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;A&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;def&lt;/span&gt; &lt;span class="nc"&gt;a1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;
  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s1"&gt;'run'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_methods&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; [:run] &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="问题："&gt;问题：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt; #&amp;lt;Class:#&amp;lt;A:0x000000010ac200&amp;gt;&amp;gt; 这是什么东西？实例变量也是一个类？&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&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;say&lt;/span&gt;
    &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s1"&gt;'say'&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;a1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="c1"&gt;#  =&amp;gt; #&amp;lt;A:0x000000010ac200&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ancestors&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; [#&amp;lt;Class:#&amp;lt;A:0x000000010ac200&amp;gt;&amp;gt;, A, Object, Kernel, BasicObject]&lt;/span&gt;

&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_methods&lt;/span&gt;
&lt;span class="c1"&gt;#  =&amp;gt; [:say]  # 因为ancestor中有 A, 所以继承了:say方法&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>breeze</author>
      <pubDate>Tue, 29 Nov 2016 17:51:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/31734</link>
      <guid>https://ruby-china.org/topics/31734</guid>
    </item>
    <item>
      <title>傻瓜是这么理解 has_one 与 belongs_to 的 primary_key, foreign_key</title>
      <description>&lt;p&gt;有人一直弄不清楚，has_one 与 belongs_to 的 primary_key 与 foreign_key 要如何设置。于是我就这么解释了！！！&lt;/p&gt;
&lt;h5 id="首先讲raIls默认的规则："&gt;首先讲 raIls 默认的规则：&lt;/h5&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="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="c1"&gt;# 当user是主人时, dog是主人的附属品时,应这样设置&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:dog&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:dog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;primary_key: :id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;foreign_key: :user_id&lt;/span&gt;
  &lt;span class="c1"&gt;# 当我们没有定义任何的primary_key与 foreign_key时&lt;/span&gt;
  &lt;span class="c1"&gt;# rails会默认拿user的主键id 与 dog的外键user_id进行关联,即 primary_key: :id, foreign_key: :user_id&lt;/span&gt;
  &lt;span class="c1"&gt;# 为什么是拿dog的user_id进行关联,因为rails默认外键的规则是: 表名_主键&lt;/span&gt;
  &lt;span class="c1"&gt;# 所以以上两种定义是等价的&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;Dog&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;

  &lt;span class="c1"&gt;# 以下两种定义也是等价的&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="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;primary_key: :id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;foreign_key: :user_id&lt;/span&gt; 

  &lt;span class="c1"&gt;# 这时候,新人就会有疑问了,怎么两个model中的primary_key与foreign_key是一样的&lt;/span&gt;
  &lt;span class="c1"&gt;# 为什么不是默认设置成:&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;primary_key: :id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;foreign_key: :dog_id&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="因为规则是: 谁是主人,primary_key就是默认主人的主键, foreign_key就是默认附属品的外键, 所以不管是has_one 还是 belongs_to他们的主人都是user。"&gt;因为规则是：谁是主人，primary_key 就是默认主人的主键，foreign_key 就是默认附属品的外键，所以不管是 has_one 还是 belongs_to 他们的主人都是 user。&lt;/h4&gt;&lt;h5 id="当默认的foreign_key不存在时"&gt;当默认的 foreign_key 不存在时&lt;/h5&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="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
&lt;span class="cm"&gt;=begin     表结构
+-----------+----------------------+------+-----+---------+----------------+
| Field     | Type                 | Null | Key | Default | Extra          |
+-----------+----------------------+------+-----+---------+----------------+
| id        | int(11) unsigned     | NO   | PRI | NULL    | auto_increment |
| name      | varchar(21)          | NO   | UNI |         |                |
+-----------+----------------------+------+-----+---------+----------------+
=end&lt;/span&gt;

  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:dog&lt;/span&gt;
  &lt;span class="c1"&gt;# 当遇到dog这张表中没有 user_id时&lt;/span&gt;
  &lt;span class="c1"&gt;# 如果使用以上关联,则会报错,因为dog表中没有rails默认外键 user_id&lt;/span&gt;

  &lt;span class="c1"&gt;# 此时,如果要成功建立关联,则需要手动指定外键&lt;/span&gt;
  &lt;span class="c1"&gt;# 当dog表中的外键字段是master_id,则需要这样设置:&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:dog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;foreign_key: :master_id&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;Dog&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
&lt;span class="cm"&gt;=begin    表结构
+-----------+----------------------+------+-----+---------+----------------+
| Field     | Type                 | Null | Key | Default | Extra          |
+-----------+----------------------+------+-----+---------+----------------+
| id        | int(11) unsigned     | NO   | PRI | NULL    | auto_increment |
| master_id | int(11) unsigned     | NO   | UNI |         |                |
+-----------+----------------------+------+-----+---------+----------------+
=end&lt;/span&gt;

  &lt;span class="c1"&gt;#同样的也需要指明foreign_key,否则通过默认规则会报错&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;foreign_key: :master_id&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>breeze</author>
      <pubDate>Fri, 30 Sep 2016 22:15:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/31217</link>
      <guid>https://ruby-china.org/topics/31217</guid>
    </item>
    <item>
      <title>Rails 5.0 API 模式中，如何在收到参数之前，就统一进行 xss 过滤？</title>
      <description>&lt;p&gt;如题。
希望像 permit(健壮参数) 一样，不需要在后续的实际业务中关心参数过滤的问题&lt;/p&gt;</description>
      <author>breeze</author>
      <pubDate>Mon, 25 Jul 2016 21:04:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/30616</link>
      <guid>https://ruby-china.org/topics/30616</guid>
    </item>
  </channel>
</rss>
