<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>caiqinghua (lin)</title>
    <link>https://ruby-china.org/caiqinghua</link>
    <description>Lin</description>
    <language>en-us</language>
    <item>
      <title>Rails I18n en.yml 缺失 本地开发调试环境和部署后表现不一致</title>
      <description>&lt;p&gt;问题：config.i18n.default_locale =  :'zh-CN'，本地调试和部署，i18n 结果不一致&lt;/p&gt;

&lt;p&gt;en.yml
en:&lt;/p&gt;

&lt;p&gt;zh-CN.yml&lt;/p&gt;

&lt;p&gt;zh-CN:
  account:
    all: 所有&lt;/p&gt;

&lt;p&gt;= t('account.all')&lt;/p&gt;

&lt;p&gt;本地调试
切换到 en
显示：All&lt;/p&gt;

&lt;p&gt;部署
切换到 en
显示：所有&lt;/p&gt;

&lt;p&gt;问题解决方案：
config.i18n.default_locale =  :en
部署和本地一致&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Mon, 10 Dec 2018 10:11:46 +0800</pubDate>
      <link>https://ruby-china.org/topics/37878</link>
      <guid>https://ruby-china.org/topics/37878</guid>
    </item>
    <item>
      <title>Rails 部署后不能启动问题定位方法</title>
      <description>&lt;p&gt;最近部署 rails 项目，遇到多起部署后不能访问的问题，记录一下排查方法&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;查看 nginx 日志&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 2000 /var/log/nginx/error.log
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 2000 /var/log/nginx/access.log
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查看 unicorn 日志 &lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 2000 path/to/current_project/log/unicorn.log

E, &lt;span class="o"&gt;[&lt;/span&gt;2015-11-09T23:29:51.154676 &lt;span class="c"&gt;#18211] ERROR -- : app error: Missing `secret_token` and `secret_key_base` for 'production' environment, set these values in `config/secrets.yml` (RuntimeError)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查看 sidekiq 日志&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 2000 path/to/current_project/log/sidekiq.log
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查看 rails 运行日志&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 2000 path/to/current_project/log/production.log
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Tue, 10 Nov 2015 00:20:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/28006</link>
      <guid>https://ruby-china.org/topics/28006</guid>
    </item>
    <item>
      <title>rake wechat:menu_create 提示 invalid sub button key size (40026) 错误</title>
      <description>&lt;h2 id="出错信息"&gt;出错信息&lt;/h2&gt;
&lt;p&gt;使用 wechat gem 包&lt;/p&gt;

&lt;p&gt;deploy@iZ94ra5tl2iZ:~/weishop_deploy/current$ RAILS_ENV=production rake wechat:menu_create
rake aborted!
Wechat::ResponseError: invalid sub button key size(40026)
/home/deploy/weishop_deploy/releases/290/vendor/bundle/ruby/2.1.0/bundler/gems/wechat-rails-5618101f1b41/lib/wechat/client.rb:42:in &lt;code&gt;block in request'
/home/deploy/weishop_deploy/releases/290/vendor/bundle/ruby/2.1.0/bundler/gems/wechat-rails-5618101f1b41/lib/wechat/client.rb:70:in&lt;/code&gt;parse_response'
/home/deploy/weishop_deploy/releases/290/vendor/bundle/ruby/2.1.0/bundler/gems/wechat-rails-5618101f1b41/lib/wechat/client.rb:31:in &lt;code&gt;request'
/home/deploy/weishop_deploy/releases/290/vendor/bundle/ruby/2.1.0/bundler/gems/wechat-rails-5618101f1b41/lib/wechat/client.rb:19:in&lt;/code&gt;post'
/home/deploy/weishop_deploy/releases/290/vendor/bundle/ruby/2.1.0/bundler/gems/wechat-rails-5618101f1b41/lib/wechat/api.rb:86:in &lt;code&gt;block in post'
/home/deploy/weishop_deploy/releases/290/vendor/bundle/ruby/2.1.0/bundler/gems/wechat-rails-5618101f1b41/lib/wechat/api.rb:92:in&lt;/code&gt;with_access_token'
/home/deploy/weishop_deploy/releases/290/vendor/bundle/ruby/2.1.0/bundler/gems/wechat-rails-5618101f1b41/lib/wechat/api.rb:86:in &lt;code&gt;post'
/home/deploy/weishop_deploy/releases/290/vendor/bundle/ruby/2.1.0/bundler/gems/wechat-rails-5618101f1b41/lib/wechat/api.rb:37:in&lt;/code&gt;menu_create'
/home/deploy/weishop_deploy/releases/290/lib/tasks/wechat.rake:7:in `block (2 levels) in '
Tasks: TOP =&amp;gt; wechat:menu_create
(See full trace by running task with --trace)&lt;/p&gt;
&lt;h2 id="原因："&gt;原因：&lt;/h2&gt;
&lt;p&gt;点击类别的菜单设置了一个网址，超出了最大长度。&lt;/p&gt;
&lt;h2 id="代码修改："&gt;代码修改：&lt;/h2&gt;
&lt;p&gt;wechat_menu.yaml&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;:name: "商城"
:sub_button:

&lt;ul&gt;
&lt;li&gt;:type: click
:name: "商城首页"
:url: '&lt;a href="http://staging.geizan.com.cn/" rel="nofollow" target="_blank"&gt;http://staging.geizan.com.cn/&lt;/a&gt;'&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;把 click 改为 view 即可解决问题&lt;/p&gt;

&lt;p&gt;杂记&lt;/p&gt;

&lt;p&gt;PG::InFailedSqlTransaction at /admin/products/000/variants
ERROR:  current transaction is aborted, commands ignored until end of transaction block&lt;/p&gt;

&lt;p&gt;google: PG::FeatureNotSupported: ERROR:  cached plan must not change result type
&lt;a href="http://stackoverflow.com/questions/2783813/postgres-8-3-error-cached-plan-must-not-change-result-type" rel="nofollow" target="_blank"&gt;http://stackoverflow.com/questions/2783813/postgres-8-3-error-cached-plan-must-not-change-result-type&lt;/a&gt;
重启 rails 服务即可&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Wed, 26 Aug 2015 00:16:03 +0800</pubDate>
      <link>https://ruby-china.org/topics/27081</link>
      <guid>https://ruby-china.org/topics/27081</guid>
    </item>
    <item>
      <title>rails 数据检验在什么时候执行？</title>
      <description>&lt;h2 id="一、先上代码"&gt;一、先上代码&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Variant&lt;/span&gt;
    &lt;span class="n"&gt;validate&lt;/span&gt; &lt;span class="ss"&gt;:check_price&lt;/span&gt;

      &lt;span class="c1"&gt;# Ensures a new variant takes the product master price when price is not supplied&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_price&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="no"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:require_master_price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s1"&gt;'No master variant found to infer price'&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;master&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s1"&gt;'Must supply price for variant or master.price for product.'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;master&lt;/span&gt;
          &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;master&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&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;currency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
          &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:currency&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LineItem&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:variant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;inverse_of: :line_items&lt;/span&gt;

    &lt;span class="n"&gt;before_validation&lt;/span&gt; &lt;span class="ss"&gt;:copy_price&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;copy_price&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt;
        &lt;span class="n"&gt;update_price&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cost_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cost_price&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cost_price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currency&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&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;h2 id="二、数据库"&gt;二、数据库&lt;/h2&gt;
&lt;p&gt;variant 数据库列中没有 currency 列&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;+----+-----------+--------+--------+-------+-------+------------+-----------+------------+------------+------------+----------+-------------+------------+-------------+------------+
| &lt;span class="nb"&gt;id&lt;/span&gt; | sku       | weight | height | width | depth | deleted_at | is_master | product_id | cost_price | cost_cu... | position | track_in... | tax_cat... | updated_at  | stock_i... |
+----+-----------+--------+--------+-------+-------+------------+-----------+------------+------------+------------+----------+-------------+------------+-------------+------------+
| 1  | R00011 | 0.0    |        |       |       |            | &lt;span class="nb"&gt;true&lt;/span&gt;      | 1          | 17.0       | USD        | 2        | &lt;span class="nb"&gt;true&lt;/span&gt;        |            | 2015-07-... | 1          |
+----+-----------+--------+--------+-------+-------+------------+-----------+------------+------------+------------+----------+-------------+------------+-------------+------------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="三、Active Record 数据验证"&gt;三、Active Record 数据验证&lt;/h2&gt;
&lt;p&gt;以下方法会做数据验证，如果验证失败就不会把对象存入数据库：
create
create!
save
save!
update
update!&lt;/p&gt;
&lt;h2 id="四、问题"&gt;四、问题&lt;/h2&gt;
&lt;p&gt;问题：variant 数据库列中没有 currency 列，所以不能持久化，但是 LineItem 中能使用 variant.currency，难道每次 variant 数据出库会执行 validate :check_price 吗？
validate :check_price 在数据创建和读取都会调用吗？read 方法也会执行数据验证吗？&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Thu, 23 Jul 2015 11:37:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/26619</link>
      <guid>https://ruby-china.org/topics/26619</guid>
    </item>
    <item>
      <title>rails delegate 代理如何验证？代理端需要验证吗？怎么验证？</title>
      <description>&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Company&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;:user&lt;/span&gt;

  &lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="ss"&gt;:mobile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:mobile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:to&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
  &lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="ss"&gt;:real_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:real_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:to&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
  &lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="ss"&gt;:nickname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:to&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
  &lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="ss"&gt;:purchase_amount_total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:to&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;

  &lt;span class="n"&gt;validates&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;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;:real_name&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;:mobile&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="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;mobile: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;mobile 怎么验证？&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Thu, 16 Jul 2015 11:37:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/26513</link>
      <guid>https://ruby-china.org/topics/26513</guid>
    </item>
    <item>
      <title>赶脚我写的是 C 代码，怎么改善为 Rails 风格？</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;has_staff_with_role?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;staffs&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;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has_role?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&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="k"&gt;return&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Thu, 16 Jul 2015 10:15:46 +0800</pubDate>
      <link>https://ruby-china.org/topics/26511</link>
      <guid>https://ruby-china.org/topics/26511</guid>
    </item>
    <item>
      <title>两种 where 查找，哪种更 Rails 风格一点？</title>
      <description>&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@staffs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Staff&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;company: &lt;/span&gt;&lt;span class="n"&gt;current_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="vi"&gt;@staffs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Staff&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;company_id: &lt;/span&gt;&lt;span class="n"&gt;current_company&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;/code&gt;&lt;/pre&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Wed, 15 Jul 2015 15:09:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/26499</link>
      <guid>https://ruby-china.org/topics/26499</guid>
    </item>
    <item>
      <title>用 FactoryGirl seed 改善重复创建问题和用例执行慢的问题</title>
      <description>&lt;h2 id="本文上下文环境"&gt;本文上下文环境&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://ruby-china.org/topics/26492" title=""&gt;Rails 测试驱动开发 Factory Girl 用例重构实践&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="factory_girl-seeds  简介"&gt;factory_girl-seeds  简介&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/evrone/factory_girl-seeds" rel="nofollow" target="_blank" title=""&gt;factory_girl-seeds github 官网&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FactoryGirl Seeds
Don't like factory_girl because it is slow? Do you know that creating records in DB through factory_girl can take up to 50% of total spec run time? And even more!&lt;/p&gt;

&lt;p&gt;This tiny gem helps fix that problem by reusing data preloaded before running test suite.&lt;/p&gt;

&lt;p&gt;好处：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;加快用例执行速度&lt;/li&gt;
&lt;li&gt;对我们的附加作用：解决重复创建问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="用factory_girl-seeds重构代码前后比较"&gt;用 factory_girl-seeds 重构代码前后比较&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/dc701e9ae0e48b9143d8d0f9dbb31cd7.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="重构后代码"&gt;重构后代码&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;support&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;login_helpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;LoginHelpers&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_staff&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:login_as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_user&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:login_as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_as_seller_user&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:seller_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:login_as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_super_admin&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;super_admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:super_admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:login_as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;super_admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_h_company_admin_staff&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;h_company_admin_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:h_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:login_as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_h_company_normal_staff&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;b_company_normal_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:h_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:login_as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;aliases: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:random_staff&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;mobile&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
    &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:random_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:super_admin&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_super_admin_role&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:company_admin&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_company_admin_role&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:normal_staff&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_normal_role&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:h_company&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:h_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&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;trait&lt;/span&gt; &lt;span class="ss"&gt;:b_company&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:b_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&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;factory&lt;/span&gt; &lt;span class="ss"&gt;:super_admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;traits: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:super_admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:h_company&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:h_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;traits: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:h_company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:company_admin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:h_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;traits: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:h_company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:normal_staff&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:b_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;traits: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:b_company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:company_admin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:b_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;traits: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:b_company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:normal_staff&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;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rails_helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:suite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:transaction&lt;/span&gt;
    &lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clean_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:truncation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prepare_factory_girl_seed_data&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;prepare_factory_girl_seed_data&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user_role_h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user_role_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user_role_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user_role_c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:h_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:b_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:t_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:c_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:h_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:b_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:terminal_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:cloud_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_super_admin_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_company_admin_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_normal_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:super_admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:h_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:h_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:b_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SeedGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:b_company_normal_staff&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>caiqinghua</author>
      <pubDate>Wed, 15 Jul 2015 11:17:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/26493</link>
      <guid>https://ruby-china.org/topics/26493</guid>
    </item>
    <item>
      <title>Rails 测试驱动开发 Factory Girl 用例重构实践</title>
      <description>&lt;h2 id="写在前面"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;一个理科生，没什么文化功底，写的不好，大家多多鼓励，希望能每每有心得或者学到新东西都分享给大家。
重构中还有很多细节不知道怎么表达出来，因为是事后回忆重构过程，所以贴的代码和过程可能有点乱，各位看官要有点耐心。&lt;/p&gt;
&lt;h3 id="先写个重构要点吧，以免看不到文章最后的同学，可以知道本文主要讲些啥玩意"&gt;先写个重构要点吧，以免看不到文章最后的同学，可以知道本文主要讲些啥玩意&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;在 data_help 中准备好测试数据，避免测试过程创建数据重复问题&lt;/li&gt;
&lt;li&gt;用 find_by 先查找数据库解决数据重复创建问题&lt;/li&gt;
&lt;li&gt;用 traits 解决数据排列组合问题&lt;/li&gt;
&lt;li&gt;用 factory girl seed 改善重复创建问题和用例执行慢的问题&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="一、本文测试对象介绍"&gt;一、本文测试对象介绍&lt;/h2&gt;&lt;h2 id="开发员工管理的特性，基本功能："&gt;开发员工管理的特性，基本功能：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;超级管理员能管理所有员工&lt;/li&gt;
&lt;li&gt;公司管理员能管理本公司的所有员工&lt;/li&gt;
&lt;li&gt;一般员工只能管理自己&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二、本文涉及的对象"&gt;二、本文涉及的对象&lt;/h2&gt;&lt;h2 id="员工角色"&gt;员工角色&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;超级管理员&lt;/li&gt;
&lt;li&gt;公司管理员&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;/li&gt;
&lt;li&gt;子公司&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三、初始代码"&gt;三、初始代码&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;

&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Cpanel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;StaffsController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :controller&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

  &lt;span class="n"&gt;login_staff&lt;/span&gt;
  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"GET #index"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"returns http success"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_http_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"super admin can see all the staffs"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
      &lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assigns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staffs&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;match_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"company admin can see all the staffs in the company"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_jack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assigns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staffs&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;match_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Staff&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;company: &lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"normal staff can only see himself"&lt;/span&gt; &lt;span class="k"&gt;do&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;describe&lt;/span&gt; &lt;span class="s2"&gt;"GET #new"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&gt;.....&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"staffs associate shops"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"a staff associate with no shop"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_jack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;staff&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="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="s2"&gt;"jack"&lt;/span&gt;

      &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Shop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

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

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

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;存在的问题&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;describe "staffs associate shops" 属于 model 测试，应该移到 model 测试文件中&lt;/li&gt;
&lt;li&gt;index 测试用登录有问题 login_staff，用的同一个用户登录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="四、重构一：超级管理员，公司管理员和普通员工分别登录测试"&gt;四、重构一：超级管理员，公司管理员和普通员工分别登录测试&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Cpanel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;StaffsController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :controller&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"GET #index"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

    &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"render index"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;login_super_admin&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"returns http success"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_http_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"super admin render index"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;login_super_admin&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"can manage all staffs"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;   
        &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assigns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staffs&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;match_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"company admin render index"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;login_head_company_admin_staff&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"can manage all staffs in the company"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;            
        &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assigns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staffs&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;match_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Staff&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;company: &lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:head_company&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"can not manage the staffs from other company"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
        &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assigns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staffs&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;not_to&lt;/span&gt; &lt;span class="kp"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Staff&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;company: &lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:branch_company&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"normal staff render index"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;login_head_company_normal_staff&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"can only manage himself"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
        &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assigns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staffs&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;match_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:head_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assigns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staffs&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&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="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;ul&gt;
&lt;li&gt;问题 login_super_admin 角色创建重复了&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="五、重构二：解决login_super_admin中重复创建staff_super_admin_role问题"&gt;五、重构二：解决 login_super_admin 中重复创建 staff_super_admin_role 问题&lt;/h2&gt;&lt;h2 id="重构前代码"&gt;重构前代码&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;staffs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;
&lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:super_admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="no"&gt;Staff&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="s1"&gt;'super_admin'&lt;/span&gt;
    &lt;span class="n"&gt;mobile&lt;/span&gt; &lt;span class="s1"&gt;'13600000001'&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;

    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;staff_roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_super_admin_role&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;end&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_super_admin&lt;/span&gt;
     &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
       &lt;span class="n"&gt;staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:super_admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:login_as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;staff&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;解决办法：在 Datahelps 中统一准备好测试数据，避免重复重建&lt;/p&gt;
&lt;h2 id="重构后代码"&gt;重构后代码&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DataHelpers&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_staffs&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@super_admin_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_super_admin_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@company_admin_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_company_admin_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@normal_staff_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_normal_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="vi"&gt;@head_company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:head_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@branch_company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:branch_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

      &lt;span class="vi"&gt;@super_admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:super_admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@super_admin.add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@super_admin_role.name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="vi"&gt;@head_company_admin_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:head_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@head_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@company_admin_role.name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@head_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@head_company&lt;/span&gt;

      &lt;span class="vi"&gt;@head_company_normal_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:head_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@head_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@normal_staff_role.name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@head_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@head_company&lt;/span&gt;

      &lt;span class="vi"&gt;@branch_company_admin_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:branch_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@branch_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@company_admin_role.name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@branch_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@branch_company&lt;/span&gt;

      &lt;span class="vi"&gt;@branch_company_normal_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:branch_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@branch_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@normal_staff_role.name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@branch_company_normal_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@branch_company&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;img src="https://l.ruby-china.com/photo/2015/781020336fda480193e674037c62427b.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="六、重构三：用traits解决排列组合数据问题（ps.用find_by先查找数据库解决数据重复创建问题）"&gt;六、重构三：用 traits 解决排列组合数据问题（ps.用 find_by 先查找数据库解决数据重复创建问题）&lt;/h2&gt;&lt;h2 id="重构前的问题"&gt;重构前的问题&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@head_company_admin_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:head_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@head_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@company_admin_role.name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@head_company_admin_staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@head_company&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;仔细查看重构二步骤中的 set_staffs 代码，如何增加一个 staff 的区域属性，发现需要修改多个地方，需要继续改善。&lt;/p&gt;
&lt;h2 id="重构后代码"&gt;重构后代码&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;factories&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;staffs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;

&lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;aliases: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:random_staff&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;mobile&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
    &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:random_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:super_admin&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
        &lt;span class="n"&gt;super_admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;StaffRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s1"&gt;'super_admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_super_admin_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;super_admin&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="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:company_admin&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
        &lt;span class="n"&gt;company_admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;StaffRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s1"&gt;'company_admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_company_admin_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company_admin&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="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:normal_staff&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
        &lt;span class="n"&gt;normal_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;StaffRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s1"&gt;'normal_staff'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:staff_normal_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normal_staff&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="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:head_company&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Company&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s1"&gt;'head_company'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:head_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:branch_company&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
      &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Company&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s1"&gt;'branch_company'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:branch_company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;support&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;data_helpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt; 

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DataHelpers&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="nf"&gt;def&lt;/span&gt; &lt;span class="n"&gt;set_staffs&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
      &lt;span class="vi"&gt;@super_admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;:staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:super_admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:head_company&lt;/span&gt;
      &lt;span class="vi"&gt;@head_company_admin_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;:staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:company_admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:head_company&lt;/span&gt;
      &lt;span class="vi"&gt;@head_company_normal_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;:staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:normal_staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:head_company&lt;/span&gt;
      &lt;span class="vi"&gt;@branch_company_admin_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;:staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:company_admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:branch_company&lt;/span&gt;
      &lt;span class="vi"&gt;@branch_company_normal_staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;:staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:normal_staff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:branch_company&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;h2 id="重构四：用factory girl seed 改善重复创建问题和用例执行慢的问题"&gt;重构四：用 factory girl seed 改善重复创建问题和用例执行慢的问题&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://ruby-china.org/topics/26493" title=""&gt;用 factory girl seed 改善重复创建问题和用例执行慢的问题&lt;/a&gt;&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Wed, 15 Jul 2015 11:09:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/26492</link>
      <guid>https://ruby-china.org/topics/26492</guid>
    </item>
    <item>
      <title>删除 GitHub 远程仓库中 master 分支的多个提交</title>
      <description>&lt;h2 id="一、本地切换到master分支"&gt;一、本地切换到 master 分支&lt;/h2&gt;
&lt;p&gt;git checkout master &lt;/p&gt;
&lt;h2 id="二、新建old_master分支备份，以防万一"&gt;二、新建 old_master 分支备份，以防万一&lt;/h2&gt;
&lt;p&gt;git branch old_master 
git push origin old_master:old_master 将本地 old_master 分支推送到远程 old_master
打开 github repo，查看 old_master 是否和 master 一致。&lt;/p&gt;
&lt;h2 id="三、删除远程master分支"&gt;三、删除远程 master 分支&lt;/h2&gt;
&lt;p&gt;设置 github 中默认分支为非 master 分支，否则，下一步删除操作被 github 禁止，github 不能删除默认分支
删除远程的 master 分支 (注意 master 前有个:)
git push origin :master&lt;/p&gt;
&lt;h2 id="四、版本回退并重新创建远程master分支"&gt;四、版本回退并重新创建远程 master 分支&lt;/h2&gt;
&lt;p&gt;本地仓库彻底回退到某一个版本
git reset --hard commit_sha(for example: a10801cc21c2dd4e6fb2d1fdcd6e1ac4fbbfebcf) 
git push origin master&lt;/p&gt;
&lt;h2 id="五、通知项目组同事本地master同步远程master分支"&gt;五、通知项目组同事本地 master 同步远程 master 分支&lt;/h2&gt;
&lt;p&gt;git reset --hard origin/master&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Fri, 03 Jul 2015 17:48:48 +0800</pubDate>
      <link>https://ruby-china.org/topics/26320</link>
      <guid>https://ruby-china.org/topics/26320</guid>
    </item>
    <item>
      <title>metaclass model, tainting, reflection, and marshaling 各自能解决什么问题？</title>
      <description>&lt;h2 id="1. 中文怎么翻译？"&gt;1. 中文怎么翻译？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;the metaclass model：元编程模型？&lt;/li&gt;
&lt;li&gt;tainting：？？？？？&lt;/li&gt;
&lt;li&gt;reflection：反射？&lt;/li&gt;
&lt;li&gt;marshaling：？？？？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2. 各自能解决为什么问题？"&gt;2. 各自能解决为什么问题？&lt;/h2&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Fri, 03 Jul 2015 09:01:30 +0800</pubDate>
      <link>https://ruby-china.org/topics/26298</link>
      <guid>https://ruby-china.org/topics/26298</guid>
    </item>
    <item>
      <title>Rack 在整个 Ruby Web 系统中处于什么位置？</title>
      <description>&lt;p&gt;&lt;em&gt;RACK 具体作用是什么，在整个 ruby web 系统中 rack 处于什么位置？rails 是怎么使用 rack 的？&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="一、RACK基本信息"&gt;一、RACK 基本信息&lt;/h3&gt;
&lt;p&gt;RACK 官网 &lt;a href="http://rack.github.io/" rel="nofollow" target="_blank"&gt;http://rack.github.io/&lt;/a&gt;
RACK spec &lt;a href="http://www.rubydoc.info/github/rack/rack/master/file/SPEC" rel="nofollow" target="_blank"&gt;http://www.rubydoc.info/github/rack/rack/master/file/SPEC&lt;/a&gt;
Rack: a Ruby Webserver Interface
Rack powers web applications
Rack provides a minimal interface between webservers that support Ruby and Ruby frameworks.&lt;/p&gt;

&lt;p&gt;To use Rack, provide an "app": an object that responds to the call method, taking the environment hash as a parameter, and returning an Array with three elements:&lt;/p&gt;

&lt;p&gt;The HTTP response code
A Hash of headers
The response body, which must respond to each
You can handle an app directly:&lt;/p&gt;
&lt;h3 id="二、RACK具体作用是什么？"&gt;二、RACK 具体作用是什么？&lt;/h3&gt;&lt;h3 id="三、在非ruby技术，和RACK类似功能的是哪些东东？php java用什么取代rack？"&gt;三、在非 ruby 技术，和 RACK 类似功能的是哪些东东？php java 用什么取代 rack？&lt;/h3&gt;&lt;h3 id="四、有没有介绍web各种技术的体系结构资料推荐？"&gt;四、有没有介绍 web 各种技术的体系结构资料推荐？&lt;/h3&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Wed, 17 Jun 2015 15:03:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/26071</link>
      <guid>https://ruby-china.org/topics/26071</guid>
    </item>
    <item>
      <title>如何优雅地把 Hash 参数传递给 JavaScript</title>
      <description>&lt;h3 id="方法一、 https://ruby-china.org/topics/9844"&gt;方法一、 &lt;a href="https://ruby-china.org/topics/9844" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/9844&lt;/a&gt;
&lt;/h3&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"order_app_id"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;%= @order_params[‘appId’] %&amp;gt;"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"order_time_stamp"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;%= @order_params[‘timeStamp’] %&amp;gt;"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="方法二、"&gt;方法二、&lt;/h3&gt;&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;javascript_tag&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  var orderParams = {
    appId:     "&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:appId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;",
    timeStamp: "&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:timeStamp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;",
    nonceStr:  "&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:nonceStr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;",
    package:   "&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:package&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;",
    signType:  "&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:signType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;"
    paySign:   "&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:paySign&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;"
  };
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="方法三、ajax"&gt;方法三、ajax&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wechat_pay_js_params&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;appid: &lt;/span&gt;&lt;span class="s1"&gt;'wx7d32820a35d2458c'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;prepay_id: &lt;/span&gt;&lt;span class="s1"&gt;'wx201506150843452f821f7b070705485969'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;_prepay_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:prepay_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;appId: &lt;/span&gt;&lt;span class="s1"&gt;'WxPay.appid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;timeStamp: &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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;nonceStr: &lt;/span&gt;&lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="ss"&gt;package: &lt;/span&gt;&lt;span class="s2"&gt;"prepay_id=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;_prepay_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;signType: &lt;/span&gt;&lt;span class="s2"&gt;"MD5"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@params&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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;/users/wechat_pay_js_params&lt;/span&gt;&lt;span class="dl"&gt;'&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="s1"&gt;JSON&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;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;response&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

                        &lt;span class="nx"&gt;WeixinJSBridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getBrandWCPayRequest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&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;res&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err_msg&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_brand_wcpay_request:ok&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/orders/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderNumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="c1"&gt;//使用以上方式判断前端返回,微信团队郑重提示：res.err_msg将在用户支付成功后返回ok，但并不保证它绝对可靠。&lt;/span&gt;
                            &lt;span class="c1"&gt;//因此微信团队建议，当收到ok返回时，向商户后台询问是否收到交易成功的通知，若收到通知，前端展示交易成功的界面；若此时未收到通知，商户后台主动调用查询订单$&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="na"&gt;error&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;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ajax: error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;别忘记设置路由&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;get&lt;/span&gt; &lt;span class="s1"&gt;'/users/wechat_pay_js_params'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:to&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"users#wechat_pay_js_params"&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="方法四、"&gt;方法四、&lt;/h3&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;WeixinJSBridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getBrandWCPayRequest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;params&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err_msg&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_brand_wcpay_request:ok&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;%= wxpay_callback_order_path(@order) %&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err_msg&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_brand_wcpay_request:cancel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;%= order_path(@order) %&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err_msg&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_brand_wcpay_request:fail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;系统错误&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;未知错误&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="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;你觉得哪种最优雅？
还有其他方法吗？&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Mon, 15 Jun 2015 18:49:01 +0800</pubDate>
      <link>https://ruby-china.org/topics/26029</link>
      <guid>https://ruby-china.org/topics/26029</guid>
    </item>
    <item>
      <title>UNICORN 和 NGINX 手动部署 rails 应用笔记</title>
      <description>&lt;h3 id="内容概要"&gt;内容概要&lt;/h3&gt;
&lt;p&gt;记录一个新手用 unicorn 和 nginx 部署 rails 应用的注意点。&lt;/p&gt;
&lt;h3 id="一、 unicorn配置"&gt;一、unicorn 配置&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;root@iZ94ra5tl2iZ:~# &lt;span class="nb"&gt;cat&lt;/span&gt; /home/deploy/weishop_origin/config/unicorn/origin.rb 
app_path &lt;span class="o"&gt;=&lt;/span&gt; File.expand_path&lt;span class="o"&gt;(&lt;/span&gt; File.join&lt;span class="o"&gt;(&lt;/span&gt;File.dirname&lt;span class="o"&gt;(&lt;/span&gt;__FILE__&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s1"&gt;'..'&lt;/span&gt;, &lt;span class="s1"&gt;'..'&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
worker_processes   1
&lt;span class="nb"&gt;timeout            &lt;/span&gt;180
listen             &lt;span class="s1"&gt;'/tmp/unicorn_origin.sock'&lt;/span&gt; &lt;span class="c"&gt;#**unicorn配置中要用到这个配置**&lt;/span&gt;
pid                &lt;span class="s2"&gt;"#{app_path}/tmp/pids/unicorn.pid"&lt;/span&gt;
stderr_path        &lt;span class="s2"&gt;"log/unicorn.log"&lt;/span&gt;
stdout_path        &lt;span class="s2"&gt;"log/unicorn.log"&lt;/span&gt;

before_fork &lt;span class="k"&gt;do&lt;/span&gt; |server, worker|
  &lt;span class="k"&gt;if &lt;/span&gt;defined?&lt;span class="o"&gt;(&lt;/span&gt;ActiveRecord::Base&lt;span class="o"&gt;)&lt;/span&gt;
    ActiveRecord::Base.connection.disconnect!
  end

  old_pid &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"#{server.config[:pid]}.oldbin"&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;File.exists?&lt;span class="o"&gt;(&lt;/span&gt;old_pid&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; server.pid &lt;span class="o"&gt;!=&lt;/span&gt; old_pid
    begin
      Process.kill&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"QUIT"&lt;/span&gt;, File.read&lt;span class="o"&gt;(&lt;/span&gt;old_pid&lt;span class="o"&gt;)&lt;/span&gt;.to_i&lt;span class="o"&gt;)&lt;/span&gt;
    rescue Errno::ENOENT, Errno::ESRCH
      &lt;span class="c"&gt;# someone else did our job for us&lt;/span&gt;
    end
  end
end

after_fork &lt;span class="k"&gt;do&lt;/span&gt; |server, worker|
  &lt;span class="k"&gt;if &lt;/span&gt;defined?&lt;span class="o"&gt;(&lt;/span&gt;ActiveRecord::Base&lt;span class="o"&gt;)&lt;/span&gt;
    ActiveRecord::Base.establish_connection
  end
end

before_exec &lt;span class="k"&gt;do&lt;/span&gt; |server| &lt;span class="c"&gt;# 修正无缝重启unicorn后更新的Gem未生效的问题，原因是config/boot.rb会优先从ENV中获取BUNDLE_GEMFILE，而无缝重启时ENV['BUNDLE_GEMFILE']的值并未被清除，仍指向旧目录的Gemfile&lt;/span&gt;
  ENV[&lt;span class="s2"&gt;"BUNDLE_GEMFILE"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"#{app_path}/Gemfile"&lt;/span&gt;
end
root@iZ94ra5tl2iZ:~# 
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="二、nginx配置"&gt;二、nginx 配置&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;root@iZ94ra5tl2iZ:~# &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/nginx/conf.d/
origin.conf      production.conf  staging.conf     
root@iZ94ra5tl2iZ:~# &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/nginx/conf.d/origin.conf 
server &lt;span class="o"&gt;{&lt;/span&gt;
  listen 80&lt;span class="p"&gt;;&lt;/span&gt;
  server_name xxx.com&lt;span class="p"&gt;;&lt;/span&gt;
  root /home/deploy/weishop/current/public&lt;span class="p"&gt;;&lt;/span&gt;

  location ^~ /assets/ &lt;span class="o"&gt;{&lt;/span&gt;
    gzip_static on&lt;span class="p"&gt;;&lt;/span&gt;
    expires max&lt;span class="p"&gt;;&lt;/span&gt;
    add_header Cache-Control public&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  try_files &lt;span class="nv"&gt;$uri&lt;/span&gt;/index.html &lt;span class="nv"&gt;$uri&lt;/span&gt; @weishop&lt;span class="p"&gt;;&lt;/span&gt;
  location @weishop &lt;span class="o"&gt;{&lt;/span&gt;
    proxy_set_header X-Forwarded-For &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_set_header Host &lt;span class="nv"&gt;$http_host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_redirect off&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_pass http://weishop&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  error_page 500 502 503 504 /500.html&lt;span class="p"&gt;;&lt;/span&gt;
  client_max_body_size 20M&lt;span class="p"&gt;;&lt;/span&gt;
  keepalive_timeout 10&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

upstream weishop &lt;span class="o"&gt;{&lt;/span&gt;
    server unix:/tmp/unicorn_production.sock &lt;span class="nv"&gt;fail_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c"&gt;#*来自unicorn配置的socket路径*&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="三、注意点"&gt;三、注意点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href="/weishop" class="user-mention" title="@weishop"&gt;&lt;i&gt;@&lt;/i&gt;weishop&lt;/a&gt;要不和已有的配置冲突&lt;/li&gt;
&lt;li&gt;unicorn 启动命令 unicorn -c config/unicorn/origin.rb -D&lt;/li&gt;
&lt;li&gt;rails s -b 0.0.0.0  运行正常，但是用 unicorn+nginx 运行，访问没有 css 效果，估计是 asset 没有安装&lt;/li&gt;
&lt;li&gt;重新执行如下命令，访问正常了。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--without&lt;/span&gt; development:test &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="s2"&gt;"./vendor/bundle"&lt;/span&gt; &lt;span class="nt"&gt;--deployment&lt;/span&gt;
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt; bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rake db:migrate
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt; bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rake assets:precompile &lt;span class="nv"&gt;RAILS_GROUPS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;assets
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问遇到如下问题
Missing &lt;code&gt;secret_token&lt;/code&gt; and &lt;code&gt;secret_key_base&lt;/code&gt; for 'production' environment, set these values in &lt;code&gt;config/secrets.yml&lt;/code&gt;
安装 figaro
在 Gemfile 中增加下行
gem figaro
在/config/application.yml 中加入 secret_key_base&lt;/p&gt;

&lt;p&gt;执行 bundle install
再次执行
bundle install --without development:test --path "./vendor/bundle" --deployment
kill unicorn 进程
启动 unicorn 进程
RAILS_ENV="production" unicorn -c /home/deploy/weishop_origin/config/unicorn/origin.rb -E deployment -D&lt;/p&gt;

&lt;p&gt;访问正常了&lt;/p&gt;
&lt;h4 id="更改 sqlite数据库为mysql数据库"&gt;更改 sqlite 数据库为 mysql 数据库&lt;/h4&gt;
&lt;p&gt;先修改 config/database.yml&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt; rake db:create
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt; rake db:migrate
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt; rake db:seed
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt; rake spree_sample:load
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更改 logo&lt;/p&gt;
&lt;h3 id="Overriding images"&gt;Overriding images&lt;/h3&gt;
&lt;p&gt;Finally, images can be replaced by substituting the required file into
the same path within your application or extension as the file you would
like to replace.&lt;/p&gt;

&lt;p&gt;For example, to replace the Spree logo you would simply copy your logo
to: &lt;code&gt;your_app/vendor/assets/images/logo/spree_50.png&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;重新执行编译资源
RAILS_ENV="production" bundle exec rake assets:precompile RAILS_GROUPS=assets&lt;/p&gt;

&lt;p&gt;*内存不够
deploy@iZ94ra5tl2iZ:~/weishop_origin$ bundle install --without development:test --path "./vendor/bundle" --deployment
Fetching source index from &lt;a href="http://ruby.taobao.org/" rel="nofollow" target="_blank"&gt;http://ruby.taobao.org/&lt;/a&gt;
/home/deploy/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/bundler-1.9.9/lib/bundler/source/git/git_proxy.rb:118:in ``': Cannot allocate memory - git (Errno::ENOMEM)&lt;/p&gt;

&lt;p&gt;kill 几个 unicorn 进程即可解决问题&lt;/p&gt;

&lt;p&gt;还有很多知识待理解&lt;/p&gt;

&lt;p&gt;bundle update --source spree_wechat_pay&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Thu, 11 Jun 2015 10:38:30 +0800</pubDate>
      <link>https://ruby-china.org/topics/25975</link>
      <guid>https://ruby-china.org/topics/25975</guid>
    </item>
    <item>
      <title>Ruby 中冒号有多少种意思？</title>
      <description>&lt;p&gt;一、问题&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Spree&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Spree&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="no"&gt;PAYMENT_STATES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w(balance_due checkout completed credit_owed failed paid pending processing void)&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;
    &lt;span class="no"&gt;SHIPMENT_STATES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w(backorder canceled partial pending ready shipped)&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;

    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;FriendlyId&lt;/span&gt;
    &lt;span class="n"&gt;friendly_id&lt;/span&gt; &lt;span class="ss"&gt;:number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;slug_column: :number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;use: :slugged&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中 slug_column 后面的冒号什么意思？是 hash key 吗？  :key =&amp;gt; value == key: value 
这一行整体怎么解释？&lt;/p&gt;

&lt;p&gt;已经求助亚飞，理解了 friendly_id( :number, {slug_column: :number, use: :slugged})&lt;/p&gt;

&lt;p&gt;二、理解 symbol
"some_string".object_id == "some_string".object_id #=&amp;gt; false
:some_string.object_id == :some_string.object_id #=&amp;gt; true&lt;/p&gt;

&lt;p&gt;这些冒号让我很困惑
&lt;a href="https://ruby-china.org/topics/15540" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/15540&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;三、跟在后面的冒号
跟在后面的冒号表示什么意思？比如 routes.rb 里的"to:"里的冒号
&lt;a href="https://ruby-china.org/topics/17907" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/17907&lt;/a&gt;
还有 migration 里的”index:“等等，
在前面是 symbol，但跟在后面是什么意思？&lt;/p&gt;

&lt;p&gt;答案：:key =&amp;gt; value == key: value
只是语法糖而已&lt;/p&gt;

&lt;p&gt;四、where to use colon (:) and where to not use it?
&lt;a href="https://www.ruby-forum.com/topic/2551601" rel="nofollow" target="_blank"&gt;https://www.ruby-forum.com/topic/2551601&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/25706" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/25706&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;五、ruby 中冒号还有哪些用法？&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Sun, 31 May 2015 15:50:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/25823</link>
      <guid>https://ruby-china.org/topics/25823</guid>
    </item>
    <item>
      <title>手动部署 PostgreSQL+PUMA+NGINX RAILS 应用</title>
      <description>&lt;h3 id="一、简介"&gt;一、简介&lt;/h3&gt;
&lt;p&gt;本文介绍在 Ubuntu14.04 上，用 PostgreSQL+PUMA+NGINX 部署 rails 应用，本文纯属学习用，所以没有用 mina 等自动部署工具，适合和我一样的新手参考阅读；
主要内容包括安装 rbenv，安装 ruby，安装 rails，安装 nodejs，安装 PostgreSQL，创建 rails 应用，安装 rbenv-vars 插件，运行创建的应用，安装配置 PUMA，安装配置 NGINX。&lt;/p&gt;
&lt;h4 id="为什么选择rbenv安装ruby"&gt;为什么选择 rbenv 安装 ruby&lt;/h4&gt;
&lt;p&gt;apt-get 安装的不是最新版本；
源码编译安装各种问题，包括编译问题，安装依赖 rubygems.org，被墙等等问题；
rbenv 安装 ruby 很顺畅，rbenv 可以安装和管理多个 ruby 版本，据说 rbenv 比 rvm 简单。&lt;/p&gt;
&lt;h4 id="为什么选择PostgreSQL"&gt;为什么选择 PostgreSQL&lt;/h4&gt;
&lt;p&gt;参考&lt;a href="http://www.zhihu.com/question/20010554" rel="nofollow" target="_blank"&gt;http://www.zhihu.com/question/20010554&lt;/a&gt;
&lt;a href="http://www.infoq.com/cn/news/2013/12/mysql-vs-postgresql" rel="nofollow" target="_blank"&gt;http://www.infoq.com/cn/news/2013/12/mysql-vs-postgresql&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="二、安装rbenv"&gt;二、安装 rbenv&lt;/h3&gt;
&lt;p&gt;更新 apt-get&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装 rben 和 ruby 的依赖&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装 rbenv 和 ruby 编译插件 参考：&lt;a href="https://github.com/sstephenson/rbenv" rel="nofollow" target="_blank"&gt;https://github.com/sstephenson/rbenv&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~
git clone git://github.com/sstephenson/rbenv.git .rbenv
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$HOME/.rbenv/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'eval "$(rbenv init -)"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt;

git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="三、安装ruby"&gt;三、安装 ruby&lt;/h3&gt;
&lt;p&gt;到官网查看最新的稳定版本号 &lt;a href="https://www.ruby-lang.org/en/downloads/" rel="nofollow" target="_blank"&gt;https://www.ruby-lang.org/en/downloads/&lt;/a&gt;
当前最新的稳定版本为 2.2.2，我们选择 2.2.2。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rbenv &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; 2.2.1
rbenv global 2.2.1
ruby &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ruby 安装完成，顺便把 bundler 也装好&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;bundler
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="四、安装rails"&gt;四、安装 rails&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;rails &lt;span class="nt"&gt;-v&lt;/span&gt; 4.2.0
rbenv rehash
rails &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="五、安装nodejs"&gt;五、安装 nodejs&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;nodejs
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="六、安装PostgreSQL"&gt;六、安装 PostgreSQL&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;postgresql postgresql-contrib libpq-dev
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="七、创建rails应用并设置数据库用户和密码"&gt;七、创建 rails 应用并设置数据库用户和密码&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;创建rails应用
rails new pumarails &lt;span class="nt"&gt;-d&lt;/span&gt; postgresql &lt;span class="nt"&gt;--skip-bundle&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;pumarails
vi Gemfile
修改rubygems.org为ruby.taobao.org，为什么，新手，你也懂的
bundle &lt;span class="nb"&gt;install

&lt;/span&gt;创建postgresql超级用户（deploy是Ubuntu14.04的一个用户）
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres createuser &lt;span class="nt"&gt;-s&lt;/span&gt; deploy
进入设置deploy的密码
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres psql
&lt;span class="se"&gt;\p&lt;/span&gt;assword deploy
退出
&lt;span class="se"&gt;\q&lt;/span&gt;

配置数据库
vi config/database.yml

username: deploy
  password: &amp;lt;%&lt;span class="o"&gt;=&lt;/span&gt; ENV[&lt;span class="s1"&gt;'PUMARAILS_DATABASE_PASSWORD'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="八、安装rbenv-vars插件"&gt;八、安装 rbenv-vars 插件&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;安装rbenv-vars插件
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.rbenv/plugins
git clone https://github.com/sstephenson/rbenv-vars.git

设置数据库密码环境变量
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/pumarails
rake secret
vi ~/.rbenv-vars
&lt;span class="nv"&gt;SECRET_KEY_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;copy_of_your_rake_secret_generated
&lt;span class="nv"&gt;PUMARAILS_DATABASE_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password_of_deploy_that_is_set_by_last_step&lt;span class="o"&gt;(&lt;/span&gt;step 7&lt;span class="o"&gt;)&lt;/span&gt;

查看设置的环境变量
rbenv vars
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="九、运行创建的应用"&gt;九、运行创建的应用&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;运行应用
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production rake db:create
rails generate scaffold Task title:string note:text
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production rake db:migrate
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production rails s &lt;span class="nt"&gt;-b&lt;/span&gt; 0.0.0.0

浏览器中打开
http://server_public_IP:3000/tasks

Ctrl+c 退出应用
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="十、安装配置PUMA"&gt;十、安装配置 PUMA&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;vi Gemfile
增加一行
gem &lt;span class="s1"&gt;'puma'&lt;/span&gt;
保存退出
bundle &lt;span class="nb"&gt;install

grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; processor /proc/cpuinfo
vi config/puma.rb

&lt;span class="c"&gt;# Change to match your CPU core count&lt;/span&gt;
workers 2
修改workers后面的2为你的CPU核的个数

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; shared/pids shared/sockets shared/log

&lt;span class="nb"&gt;cd&lt;/span&gt; ~
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/upstart/puma-manager.conf
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/upstart/puma.conf

vi puma.conf

修改uid和gid为deploy
setuid deploy
setgid deploy

&lt;span class="nb"&gt;sudo cp &lt;/span&gt;puma.conf puma-manager.conf /etc/init

&lt;span class="nb"&gt;sudo &lt;/span&gt;vi /etc/puma.conf
加入下行，保存退出
/home/deploy/pumarails
&lt;span class="nb"&gt;sudo &lt;/span&gt;start puma-manager
&lt;span class="nb"&gt;sudo &lt;/span&gt;start puma &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/deploy/pumarails
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="十一、安装配置NGINX"&gt;十一、安装配置 NGINX&lt;/h3&gt;
&lt;p&gt;官方安装参考链接：&lt;a href="http://wiki.nginx.org/Install" rel="nofollow" target="_blank"&gt;http://wiki.nginx.org/Install&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt;
&lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;stable &lt;span class="c"&gt;# use nginx=development for latest development version&lt;/span&gt;
add-apt-repository ppa:nginx/&lt;span class="nv"&gt;$nginx&lt;/span&gt;
apt-get update 
apt-get &lt;span class="nb"&gt;install &lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vi ~./nginx_puma_conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;copy 以下内容，保存退出&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;upstream app &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# Path to Puma SOCK file, as defined previously&lt;/span&gt;
    server unix:/home/deploy/appname/shared/sockets/puma.sock &lt;span class="nv"&gt;fail_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 80&lt;span class="p"&gt;;&lt;/span&gt;
    server_name localhost&lt;span class="p"&gt;;&lt;/span&gt;

    root /home/deploy/appname/public&lt;span class="p"&gt;;&lt;/span&gt;

    try_files &lt;span class="nv"&gt;$uri&lt;/span&gt;/index.html &lt;span class="nv"&gt;$uri&lt;/span&gt; @app&lt;span class="p"&gt;;&lt;/span&gt;

    location @app &lt;span class="o"&gt;{&lt;/span&gt;
        proxy_pass http://app&lt;span class="p"&gt;;&lt;/span&gt;
        proxy_set_header X-Forwarded-For &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        proxy_set_header Host &lt;span class="nv"&gt;$http_host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        proxy_redirect off&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    error_page 500 502 503 504 /500.html&lt;span class="p"&gt;;&lt;/span&gt;
    client_max_body_size 4G&lt;span class="p"&gt;;&lt;/span&gt;
    keepalive_timeout 10&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo cp&lt;/span&gt; ~./nginx_puma_conf /etc/nginx/sites-available/default
&lt;span class="nb"&gt;sudo &lt;/span&gt;service nginx restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;浏览器访问&lt;a href="http://server_public_IP/tasks" rel="nofollow" target="_blank"&gt;http://server_public_IP/tasks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;恭喜同是新手的你，你已经部署好了一个 rails 应用。&lt;/p&gt;
&lt;h3 id="十二、总结"&gt;十二、总结&lt;/h3&gt;
&lt;p&gt;本文内容中的亮点
rbenv 安装 ruby，简单控制 ruby 版本
rbenv-vars，保证密码不被上传到代码库
puma，最新的 rails 并发工具 (大家自行去比较 Passenger or Unicorn)&lt;/p&gt;

&lt;p&gt;参考教程：&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04" rel="nofollow" target="_blank"&gt;https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04&lt;/a&gt;&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Wed, 27 May 2015 21:12:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/25774</link>
      <guid>https://ruby-china.org/topics/25774</guid>
    </item>
    <item>
      <title>如何定位 Puma + Nginx 部署问题 404 not found (on Ubuntu 14.04) </title>
      <description>&lt;p&gt;参考如下教程，完成后访问显示 404 错误
&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04" rel="nofollow" target="_blank"&gt;https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;一、&lt;a href="http://ip:3000/tasks" rel="nofollow" target="_blank"&gt;http://ip:3000/tasks&lt;/a&gt; 能正常访问&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;pumarails/
~/pumarails&lt;span class="nv"&gt;$ RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production rails server &lt;span class="nt"&gt;-b&lt;/span&gt; 0.0.0.0
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; Booting Puma
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; Rails 4.2.1 application starting &lt;span class="k"&gt;in &lt;/span&gt;production on http://0.0.0.0:3000
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; Run &lt;span class="sb"&gt;`&lt;/span&gt;rails server &lt;span class="nt"&gt;-h&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more startup options
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; Ctrl-C to shutdown server
Puma 2.11.3 starting...
&lt;span class="k"&gt;*&lt;/span&gt; Min threads: 0, max threads: 16
&lt;span class="k"&gt;*&lt;/span&gt; Environment: production
&lt;span class="k"&gt;*&lt;/span&gt; Listening on tcp://0.0.0.0:3000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;二、nginx 能正常访问 index.html&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ip/tasks" rel="nofollow" target="_blank"&gt;http://ip/tasks&lt;/a&gt; 访问显示 404 错误&lt;/p&gt;

&lt;p&gt;404 Not Found&lt;/p&gt;

&lt;p&gt;nginx/1.8.0&lt;/p&gt;

&lt;p&gt;三、PUMA 配置&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deploy@iZ94ra5tl2iZ:~/pumarails&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;config/puma.rb 
&lt;span class="c"&gt;# Change to match your CPU core count&lt;/span&gt;
workers 1

&lt;span class="c"&gt;# Min and Max threads per worker&lt;/span&gt;
threads 1, 6

app_dir &lt;span class="o"&gt;=&lt;/span&gt; File.expand_path&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../.."&lt;/span&gt;, __FILE__&lt;span class="o"&gt;)&lt;/span&gt;
shared_dir &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"#{app_dir}/shared"&lt;/span&gt;

&lt;span class="c"&gt;# Default to production&lt;/span&gt;
rails_env &lt;span class="o"&gt;=&lt;/span&gt; ENV[&lt;span class="s1"&gt;'RAILS_ENV'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"production"&lt;/span&gt;
environment rails_env

&lt;span class="c"&gt;# Set up socket location&lt;/span&gt;
&lt;span class="nb"&gt;bind&lt;/span&gt; &lt;span class="s2"&gt;"unix://#{shared_dir}/sockets/puma.sock"&lt;/span&gt;

&lt;span class="c"&gt;# Logging&lt;/span&gt;
stdout_redirect &lt;span class="s2"&gt;"#{shared_dir}/log/puma.stdout.log"&lt;/span&gt;, &lt;span class="s2"&gt;"#{shared_dir}/log/puma.stderr.log"&lt;/span&gt;, &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Set master PID and state locations&lt;/span&gt;
pidfile &lt;span class="s2"&gt;"#{shared_dir}/pids/puma.pid"&lt;/span&gt;
state_path &lt;span class="s2"&gt;"#{shared_dir}/pids/puma.state"&lt;/span&gt;
activate_control_app

on_worker_boot &lt;span class="k"&gt;do
  &lt;/span&gt;require &lt;span class="s2"&gt;"active_record"&lt;/span&gt;
  ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
  ActiveRecord::Base.establish_connection&lt;span class="o"&gt;(&lt;/span&gt;YAML.load_file&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"#{app_dir}/config/database.yml"&lt;/span&gt;&lt;span class="o"&gt;)[&lt;/span&gt;rails_env]&lt;span class="o"&gt;)&lt;/span&gt;
end
deploy@iZ94ra5tl2iZ:~/pumarails&lt;span class="nv"&gt;$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;四、nginx 配置&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deploy@iZ94ra5tl2iZ:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/nginx/sites-available/default

upstream app &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# Path to Puma SOCK file, as defined previously&lt;/span&gt;
    server unix:/home/deploy/pumarails/shared/sockets/puma.sock &lt;span class="nv"&gt;fail_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 80&lt;span class="p"&gt;;&lt;/span&gt;
    server_name localhost&lt;span class="p"&gt;;&lt;/span&gt;

    root /home/deploy/pumarails/public&lt;span class="p"&gt;;&lt;/span&gt;

    try_files &lt;span class="nv"&gt;$uri&lt;/span&gt;/index.html &lt;span class="nv"&gt;$uri&lt;/span&gt; @app&lt;span class="p"&gt;;&lt;/span&gt;

    location @app &lt;span class="o"&gt;{&lt;/span&gt;
        proxy_pass http://app&lt;span class="p"&gt;;&lt;/span&gt;
        proxy_set_header X-Forwarded-For &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        proxy_set_header Host &lt;span class="nv"&gt;$http_host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        proxy_redirect off&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    error_page 500 502 503 504 /500.html&lt;span class="p"&gt;;&lt;/span&gt;
    client_max_body_size 4G&lt;span class="p"&gt;;&lt;/span&gt;
    keepalive_timeout 10&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
deploy@iZ94ra5tl2iZ:~&lt;span class="nv"&gt;$ &lt;/span&gt;


deploy@iZ94ra5tl2iZ:~/pumarails&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/nginx/sites-available/default 
&lt;span class="c"&gt;##&lt;/span&gt;
&lt;span class="c"&gt;# You should look at the following URL's in order to grasp a solid understanding&lt;/span&gt;
&lt;span class="c"&gt;# of Nginx configuration files in order to fully unleash the power of Nginx.&lt;/span&gt;
&lt;span class="c"&gt;# http://wiki.nginx.org/Pitfalls&lt;/span&gt;
&lt;span class="c"&gt;# http://wiki.nginx.org/QuickStart&lt;/span&gt;
&lt;span class="c"&gt;# http://wiki.nginx.org/Configuration&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Generally, you will want to move this file somewhere, and start with a clean&lt;/span&gt;
&lt;span class="c"&gt;# file but keep this around for reference. Or just disable in sites-enabled.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.&lt;/span&gt;
&lt;span class="c"&gt;##&lt;/span&gt;

&lt;span class="c"&gt;# Default server configuration&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
upstream app &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# Path to Puma SOCK file, as defined previously&lt;/span&gt;
    server unix:///home/deploy/pumarails/shared/sockets/puma.sock &lt;span class="nv"&gt;fail_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 80 default_server&lt;span class="p"&gt;;&lt;/span&gt;
    listen &lt;span class="o"&gt;[&lt;/span&gt;::]:80 default_server&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c"&gt;# SSL configuration&lt;/span&gt;
    &lt;span class="c"&gt;#&lt;/span&gt;
    &lt;span class="c"&gt;# listen 443 ssl default_server;&lt;/span&gt;
    &lt;span class="c"&gt;# listen [::]:443 ssl default_server;&lt;/span&gt;
    &lt;span class="c"&gt;#&lt;/span&gt;
    &lt;span class="c"&gt;# Note: You should disable gzip for SSL traffic.&lt;/span&gt;
    &lt;span class="c"&gt;# See: https://bugs.debian.org/773332&lt;/span&gt;
    &lt;span class="c"&gt;#&lt;/span&gt;
    &lt;span class="c"&gt;# Read up on ssl_ciphers to ensure a secure configuration.&lt;/span&gt;
    &lt;span class="c"&gt;# See: https://bugs.debian.org/765782&lt;/span&gt;
    &lt;span class="c"&gt;#&lt;/span&gt;
    &lt;span class="c"&gt;# Self signed certs generated by the ssl-cert package&lt;/span&gt;
    &lt;span class="c"&gt;# Don't use them in a production server!&lt;/span&gt;
    &lt;span class="c"&gt;#&lt;/span&gt;
    &lt;span class="c"&gt;# include snippets/snakeoil.conf;&lt;/span&gt;

    &lt;span class="c"&gt;#root /var/www/html;&lt;/span&gt;
    root /home/deploy/pumarails/public&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c"&gt;# Add index.php to the list if you are using PHP&lt;/span&gt;
    index index.html index.htm index.nginx-debian.html&lt;span class="p"&gt;;&lt;/span&gt;

    server_name _&lt;span class="p"&gt;;&lt;/span&gt;

    location / &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;# First attempt to serve request as file, then&lt;/span&gt;
        &lt;span class="c"&gt;# as directory, then fall back to displaying a 404.&lt;/span&gt;
        try_files &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;/ &lt;span class="o"&gt;=&lt;/span&gt;404&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000&lt;/span&gt;
    &lt;span class="c"&gt;#&lt;/span&gt;
    &lt;span class="c"&gt;#location ~ \.php$ {&lt;/span&gt;
    &lt;span class="c"&gt;#   include snippets/fastcgi-php.conf;&lt;/span&gt;
    &lt;span class="c"&gt;#&lt;/span&gt;
    &lt;span class="c"&gt;#   # With php5-cgi alone:&lt;/span&gt;
    &lt;span class="c"&gt;#   fastcgi_pass 127.0.0.1:9000;&lt;/span&gt;
    &lt;span class="c"&gt;#   # With php5-fpm:&lt;/span&gt;
    &lt;span class="c"&gt;#   fastcgi_pass unix:/var/run/php5-fpm.sock;&lt;/span&gt;
    &lt;span class="c"&gt;#}&lt;/span&gt;

    &lt;span class="c"&gt;# deny access to .htaccess files, if Apache's document root&lt;/span&gt;
    &lt;span class="c"&gt;# concurs with nginx's one&lt;/span&gt;
    &lt;span class="c"&gt;#&lt;/span&gt;
    &lt;span class="c"&gt;#location ~ /\.ht {&lt;/span&gt;
    &lt;span class="c"&gt;#   deny all;&lt;/span&gt;
    &lt;span class="c"&gt;#}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="c"&gt;# Virtual Host configuration for example.com&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# You can move that to a different file under sites-available/ and symlink that&lt;/span&gt;
&lt;span class="c"&gt;# to sites-enabled/ to enable it.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;#server {&lt;/span&gt;
&lt;span class="c"&gt;#   listen 80;&lt;/span&gt;
&lt;span class="c"&gt;#   listen [::]:80;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;#   server_name example.com;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;#   root /var/www/example.com;&lt;/span&gt;
&lt;span class="c"&gt;#   index index.html;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;#   location / {&lt;/span&gt;
&lt;span class="c"&gt;#       try_files $uri $uri/ =404;&lt;/span&gt;
&lt;span class="c"&gt;#   }&lt;/span&gt;
&lt;span class="c"&gt;#}&lt;/span&gt;
deploy@iZ94ra5tl2iZ:~/pumarails&lt;span class="nv"&gt;$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;五、如何定位此问题&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Wed, 27 May 2015 17:21:54 +0800</pubDate>
      <link>https://ruby-china.org/topics/25767</link>
      <guid>https://ruby-china.org/topics/25767</guid>
    </item>
    <item>
      <title>局域网中的手机访问 rails server 方法</title>
      <description>&lt;p&gt;rails s
&lt;a href="http://localhost:3000" rel="nofollow" target="_blank"&gt;http://localhost:3000&lt;/a&gt; 访问正常
本机 ip 为 192.168.1.102
本机或手机访问 &lt;a href="http://192.168.1.102:3000" rel="nofollow" target="_blank"&gt;http://192.168.1.102:3000&lt;/a&gt; 访问不成功&lt;/p&gt;

&lt;p&gt;解决方法
rails s -b 192.168.1.102
&lt;a href="http://192.168.1.102:3000" rel="nofollow" target="_blank"&gt;http://192.168.1.102:3000&lt;/a&gt; 局域网中的电脑和手机都可以访问 rails server 了。&lt;/p&gt;

&lt;p&gt;baidu: rails 局域网  访问
&lt;a href="https://ruby-china.org/topics/889" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/889&lt;/a&gt;&lt;/p&gt;</description>
      <author>caiqinghua</author>
      <pubDate>Fri, 24 Apr 2015 22:37:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/25305</link>
      <guid>https://ruby-china.org/topics/25305</guid>
    </item>
  </channel>
</rss>
