<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>zfben (朱峰)</title>
    <link>https://ruby-china.org/zfben</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>[北京][东直门] 简单心理招聘 Ruby 工程师一名 (15 ~ 23k)</title>
      <description>&lt;h2 id="关于简单心理"&gt;关于简单心理&lt;/h2&gt;
&lt;p&gt;简单心理隶属于北京竹间科技有限公司。简单心理专注于提供高质量心理服务，是国内优质的心理咨询平台，也是样本规模较大的心理咨询医疗大数据平台，2014 年 5 月成立于中国北京。&lt;/p&gt;
&lt;h2 id="简单心理正在做些什么？"&gt;简单心理正在做些什么？&lt;/h2&gt;
&lt;p&gt;我们在做心理健康服务领域的标杆，我们培养、监督、选择数量有限的专业心理咨询师和相关领域的从业者，生产靠谱的心理服务产品，为有心理健康帮助需求的用户提供有偿服务。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;目前，已有超过 10 万次心理咨询在简单心理发生；&lt;/li&gt;
&lt;li&gt;用严苛的标准筛选国内及海外的心理服务者入驻，参考美国心理学会（APA）标准；&lt;/li&gt;
&lt;li&gt;来自全球 80+ 城市 400 余名个体心理咨询师（Individual Counsellors）、数十名团体心理咨询师（Group Therapists）以及上百名倾听者 (Active Listeners) 提供服务。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;面向来访者的服务&lt;/strong&gt;：简单心理面向大众提供心理咨询相关的专业的、多样化服务，包括心理咨询、精神科顾问、倾诉热线、线上课程、线下课程及活动、心理科普自媒体、心理评估；&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面向企业客户的服务&lt;/strong&gt;：简单心理为企业提供定制化专业心理服务，包括企业心理课程、员工心理咨询、危机咨询等，已服务过的客户包括嫣然天使基金、上海家化、中国联通、国家电网等企业；&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面向咨询师的服务&lt;/strong&gt;：简单心理为这些心理服务提供者提供执业的行政支持、专业学习支持、督导支持，并对服务进行监督和管理；&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面向心理咨询学习者&lt;/strong&gt;：简单心理优选海内外优质教员和督导，为入门咨询师提供系统的基础训练，并帮助搭建实习平台，搭建完善咨询师专业成长路径；&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面向行业&lt;/strong&gt;：简单心理和国内外知名的研究机构合作，进行心理咨询行业的数据统计分析、干预方法的比较研究等学术研究项目，助力咨询行业发展。&lt;/p&gt;
&lt;h2 id="企业福利"&gt;企业福利&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;舒适的办公环境&lt;/li&gt;
&lt;li&gt;提供 Macbook Pro 和外置显示器&lt;/li&gt;
&lt;li&gt;五险一金&lt;/li&gt;
&lt;li&gt;做五休二，法定休假&lt;/li&gt;
&lt;li&gt;带薪年假&lt;/li&gt;
&lt;li&gt;不定期的内部分享（内容涵盖从咖啡的煮法到运营数据分析）&lt;/li&gt;
&lt;li&gt;免费午餐&lt;/li&gt;
&lt;li&gt;心理咨询抵扣券及各种内部商品&amp;amp;服务的超值特价&lt;/li&gt;
&lt;li&gt;可报销部分学习费用&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="技术栈"&gt;技术栈&lt;/h2&gt;
&lt;p&gt;客户端涵盖 Web、安卓、iOS、微信公众号/服务号/小程序；&lt;/p&gt;

&lt;p&gt;后端框架为 Ruby 2.4 + Rails 5.1，数据库包括 PostgreSQL、Mysql、Redis 和 Elasticsearch；&lt;/p&gt;

&lt;p&gt;服务器托管于阿里云，并使用了阿里云的多种服务。&lt;/p&gt;
&lt;h2 id="招聘详情"&gt;招聘详情&lt;/h2&gt;
&lt;p&gt;职位：Ruby 工程师（一名）&lt;/p&gt;

&lt;p&gt;工作地点：北京 · 东直门附近&lt;/p&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;2 ~ 3 年 Ruby 开发经验&lt;/li&gt;
&lt;li&gt;掌握 Git 版本控制工具&lt;/li&gt;
&lt;li&gt;掌握面向对象编程的概念和最佳实践&lt;/li&gt;
&lt;li&gt;掌握 Web 应用相关的标准和最佳实践&lt;/li&gt;
&lt;li&gt;熟悉 PostgreSQL、Redis、Elasticsearch 等常用数据库和引擎&lt;/li&gt;
&lt;li&gt;熟悉 Linux / Unix 操作系统&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;有 Ruby 相关的开源项目（可以是 fork 后修改的项目）&lt;/li&gt;
&lt;li&gt;熟悉 Docker&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;p&gt;请将你的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;简历&lt;/li&gt;
&lt;li&gt;联系方式&lt;/li&gt;
&lt;li&gt;期望薪资&lt;/li&gt;
&lt;li&gt;开源项目网址&lt;/li&gt;
&lt;li&gt;近期能够代表你编程水平的&lt;strong&gt;代码片段&lt;/strong&gt;（如果开源项目的代码不足以代表你的水平的话）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;发送至 &lt;a href="mailto:ben@jiandanxinli.com" title=""&gt;ben@jiandanxinli.com&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;我们收到后会在 24 小时内通过邮件、电话或你注明的联系方式联系你（节假日除外）。&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Wed, 03 Jan 2018 15:38:19 +0800</pubDate>
      <link>https://ruby-china.org/topics/34812</link>
      <guid>https://ruby-china.org/topics/34812</guid>
    </item>
    <item>
      <title>[北京][东直门] 简单心理招聘 Ruby 工程师一名 (15 ~ 20k)</title>
      <description>&lt;p&gt;三喵镇楼 (ฅ ˃̶̀ω˂̶́ ฅ)&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/4a5030d7-44c8-4468-b364-fd253353730c.jpeg!large" title="" alt="三喵"&gt;&lt;/p&gt;

&lt;p&gt;秋高气爽，佳节临近之际，简单心理搬入了新办公室，开始招募新成员啦！&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;简单心理投资方为硅谷和国内一线 VC：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NEA&lt;/strong&gt; 是一家覆盖全球的 VC。自成立以来，管理总计 170 亿美元的基金，活跃于科技和医疗领域。所投公司中，已经有 200 家企业上市，另有 320 被收购。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;真格基金&lt;/strong&gt; 由著名天使投资人徐小平创办。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tim Draper&lt;/strong&gt; 硅谷投资机构 DFJ 创始人之一，先后投资过 Skype, Tesla。简单心理是 Tim Draper 继百度之后，投资的第二家中国企业。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;华创资本&lt;/strong&gt; 关注早期创业项目。&lt;/p&gt;

&lt;p&gt;2016 年初获得数百万美金 A 轮融资。&lt;/p&gt;
&lt;h2 id="企业福利"&gt;企业福利&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;舒适的办公环境&lt;/li&gt;
&lt;li&gt;提供 Macbook Pro 和外置显示器&lt;/li&gt;
&lt;li&gt;五险一金&lt;/li&gt;
&lt;li&gt;做五休二，法定休期（偶尔也有额外假期，比如今年春节有 9 天假期）&lt;/li&gt;
&lt;li&gt;带薪年假&lt;/li&gt;
&lt;li&gt;不定期的内部分享（内容涵盖从咖啡的煮法到运营数据分析）&lt;/li&gt;
&lt;li&gt;免费午餐及各种水果零食和饮料&lt;/li&gt;
&lt;li&gt;心理咨询抵扣券&lt;/li&gt;
&lt;li&gt;可报销部分学习费用&lt;/li&gt;
&lt;li&gt;萌宠鼓励师 (ฅ ˃̶̀ω˂̶́ ฅ)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="团队文化"&gt;团队文化&lt;/h2&gt;
&lt;p&gt;拥抱变化：客户端涵盖 Web、安卓、iOS、微信公众号/服务号/小程序；后端框架为 Ruby 2.4.1 + Rails 5.1.4，数据库为 Postgresql，数据仓库为 Hadoop。&lt;/p&gt;

&lt;p&gt;拥抱不同：社交恐惧？LGBT？都不是问题，我们接纳真实的你。&lt;/p&gt;
&lt;h2 id="招聘详情"&gt;招聘详情&lt;/h2&gt;
&lt;p&gt;职位：Ruby 工程师（一名）&lt;/p&gt;

&lt;p&gt;工作地点：北京 · 东直门附近&lt;/p&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;熟练掌握 Ruby 编程语言和 Ruby on Rails 框架以及&lt;strong&gt;两年及以上相关开发经验&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;掌握 Git 版本控制工具&lt;/li&gt;
&lt;li&gt;掌握面向对象编程的概念和最佳实践&lt;/li&gt;
&lt;li&gt;掌握 Web 应用相关的标准和最佳实践&lt;/li&gt;
&lt;li&gt;扎实的计算机科学基础知识，熟悉操作系统，数据库、常见数据结构和算法，以及软件设计实践&lt;/li&gt;
&lt;li&gt;熟悉 Linux / Unix 操作系统&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;有 Ruby 相关的开源项目（可以是 fork 后修改的项目）&lt;/li&gt;
&lt;li&gt;熟悉 Go 语言&lt;/li&gt;
&lt;li&gt;熟悉 Docker&lt;/li&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;p&gt;请将你的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;简历&lt;/li&gt;
&lt;li&gt;联系方式&lt;/li&gt;
&lt;li&gt;期望薪资&lt;/li&gt;
&lt;li&gt;开源项目网址&lt;/li&gt;
&lt;li&gt;近期能够代表你编程水平的&lt;strong&gt;代码片段&lt;/strong&gt;（如果开源项目的代码不足以代表你的水平的话）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;发送至 &lt;a href="mailto:ben@jiandanxinli.com" title=""&gt;ben@jiandanxinli.com&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;我们收到后会在 24 小时内通过邮件、电话或你注明的联系方式联系你（节假日除外）。&lt;/p&gt;
&lt;h2 id="了解更多"&gt;了解更多&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.jiandanxinli.com/about" rel="nofollow" target="_blank" title=""&gt;关于简单心理&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://mp.weixin.qq.com/s/9N-rTGvoTNhtMsfi5AWePg" rel="nofollow" target="_blank" title=""&gt;（彩蛋）简单心理优秀员工的一天&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jiandanxinli.com/report2016" rel="nofollow" target="_blank" title=""&gt;2016 心理健康认知度与心理咨询行业调查报告&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jiandanxinli.com/pages/37" rel="nofollow" target="_blank" title=""&gt;更多可加入的岗位&lt;/a&gt;&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Mon, 18 Sep 2017 14:34:03 +0800</pubDate>
      <link>https://ruby-china.org/topics/34162</link>
      <guid>https://ruby-china.org/topics/34162</guid>
    </item>
    <item>
      <title>使用 Subscriber 来管理 Model Callbacks [北京 Rubyists 活动分享]</title>
      <description>&lt;blockquote&gt;
&lt;p&gt;这次 Ruby 线下聚会，我只做了个简单的 5 分钟分享，但收获了不少知识和技术观点，下面是加上后来反思的内容后，补充完善的分享内容。欢迎大家继续讨论，也希望大家踊跃报名下次线下聚会的分享~&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="场景及问题"&gt;场景及问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;随着业务的复杂化，Model 间互相调用的情况越来越多&lt;/li&gt;
&lt;li&gt;但大部分情况下如果封装 service 层又过于复杂&lt;/li&gt;
&lt;li&gt;于是 callback 里堆积了大量操作，导致 model 文件越来越长&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="解决方法"&gt;解决方法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;用观察者模式，监听 model callback 触发&lt;/li&gt;
&lt;li&gt;用约定来清晰划分代码位置&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="简单栗子"&gt;简单栗子&lt;/h2&gt;
&lt;p&gt;当更新商品价格时，需要更新相关订单的价格。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:orders&lt;/span&gt;

  &lt;span class="n"&gt;after_update&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;price_changed?&lt;/span&gt;
      &lt;span class="n"&gt;orders&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;order&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt; &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;price&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;h2 id="使用 Subscriber 后"&gt;使用 Subscriber 后&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ./app/subscribers/order_subscriber.rb&lt;/span&gt;
&lt;span class="n"&gt;subscribe_model&lt;/span&gt; &lt;span class="ss"&gt;:product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:after_update&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;price_changed?&lt;/span&gt;
    &lt;span class="n"&gt;orders&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;order&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt; &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;price&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="使用约定"&gt;使用约定&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;只有与别的 model 交互的业务，才能写到 subscriber 中&lt;/li&gt;
&lt;li&gt;subscriber 中不能修改触发 model&lt;/li&gt;
&lt;li&gt;业务代码放置在消费该触发的 subscriber 里&lt;/li&gt;
&lt;li&gt;如果单个 subscriber 太长，也可以按业务切分成多个 subscriber，如 order_product_subscriber.rb&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="好处"&gt;好处&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;model 文件中不再包含大量 callback&lt;/li&gt;
&lt;li&gt;每个 model 需要消费哪些其它 model 一目了然&lt;/li&gt;
&lt;li&gt;after_save 类的 callback，依然是被包裹在一个 transaction 中&lt;/li&gt;
&lt;li&gt;支持二级 model 的回调（会先触发二级 model 的 callbacks，再触发 base_class 的 callbacks）&lt;/li&gt;
&lt;li&gt;可以单独写测试（基于 ActiveSupport::Notifications）&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="c1"&gt;# ./config/initializers/subscribe_model.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subscribe_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"active_record.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;event_name&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="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_started&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_finished&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_unique_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:model&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;instance_eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="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;ActiveRecord::Base&lt;/span&gt;
  &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="ss"&gt;:skip_model_subscribers&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;skip_model_subscribers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="sx"&gt;%i(after_create after_update after_destroy after_save after_commit after_create_commit after_update_commit)&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="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;|&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;public_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;skip_model_subscribers&lt;/span&gt;
      &lt;span class="n"&gt;readonly!&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;readonly?&lt;/span&gt;
      &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instrument&lt;/span&gt; &lt;span class="s2"&gt;"active_record.&lt;/span&gt;&lt;span class="si"&gt;#{&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;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singular&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;model: &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;
      &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instrument&lt;/span&gt; &lt;span class="s2"&gt;"active_record.&lt;/span&gt;&lt;span class="si"&gt;#{&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;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;base_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singular&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;model: &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="k"&gt;if&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;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;base_class&lt;/span&gt; &lt;span class="o"&gt;!=&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;class&lt;/span&gt;
      &lt;span class="n"&gt;public_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:instance_variable_set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:@readonly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&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="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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after_initialize&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app/subscribers/*.rb'&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="FAQ"&gt;FAQ&lt;/h2&gt;
&lt;p&gt;Q: 为什么不用 concern？&lt;/p&gt;

&lt;p&gt;A: 团队内部约定，只有两个及以上的 model 有共用代码，才能移到 concern。&lt;/p&gt;

&lt;p&gt;Q: 为什么不创建 service 层？&lt;/p&gt;

&lt;p&gt;A: service 层不够直观，而且对于小型团队来说，维护成本高于 subscriber。&lt;/p&gt;

&lt;p&gt;转自 &lt;a href="https://jiandanxinli.github.io/2017-03-27.html" rel="nofollow" target="_blank"&gt;https://jiandanxinli.github.io/2017-03-27.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Tue, 28 Mar 2017 10:51:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/32649</link>
      <guid>https://ruby-china.org/topics/32649</guid>
    </item>
    <item>
      <title>[北京][2017年3月25日 周六] Ruby 聚会</title>
      <description>&lt;p&gt;地点：三元桥 时间国际 8 号楼 2 层 01 室
时间：3/25 周六 下午 2 点&lt;/p&gt;

&lt;p&gt;本次场地由 &lt;a href="http://www.fishtrip.cn/" rel="nofollow" target="_blank" title=""&gt;大鱼自助游&lt;/a&gt; 提供。&lt;/p&gt;

&lt;p&gt;饮料请自带，本次活动不提供餐饮。（PS. 楼下有便利店）&lt;/p&gt;

&lt;p&gt;无需报名，届时前往即可。&lt;/p&gt;

&lt;p&gt;分享话题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;《程序员的未来出路》 - 明创软件 / 申思维&lt;/li&gt;
&lt;li&gt;《使用 subscriber 来管理 model callback》 - 简单心理 / 朱峰&lt;/li&gt;
&lt;li&gt;《从零开始构建一个简单的 ORM》 - 大鱼自助游 / 黄轩宇&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>zfben</author>
      <pubDate>Mon, 27 Feb 2017 11:52:47 +0800</pubDate>
      <link>https://ruby-china.org/topics/32390</link>
      <guid>https://ruby-china.org/topics/32390</guid>
    </item>
    <item>
      <title>Turbolinks 介绍及使用技巧 · Turbolinks Part 1</title>
      <description>&lt;p&gt;Turbolinks 是源自 Ruby on Rails 的 Web 加载优化方案。简单来说就是当用户点击链接时，并不真实的跳转网页，而是通过 ajax 读取目标页的内容，然后替换当前页。这种方式有以下优点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;避免 Javascript 和 CSS 的重新加载&lt;/li&gt;
&lt;li&gt;减少网页的重新渲染的工作量&lt;/li&gt;
&lt;li&gt;对搜索引擎友好&lt;/li&gt;
&lt;li&gt;无须后端改动&lt;/li&gt;
&lt;li&gt;支持 App 端（有 Android 和 iOS SDK）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;以上是功能性的优点，除此之外，这种传统的“页面”形式的交互，也能让用户更易于理解（虽然现在更流行应用式的交互，但这对设计师的要求更高，设计的不好很容易让用户迷路）。&lt;/p&gt;
&lt;h2 id="安装 Turbolinks"&gt;安装 Turbolinks&lt;/h2&gt;
&lt;p&gt;见 &lt;a href="https://github.com/turbolinks/turbolinks" rel="nofollow" target="_blank"&gt;https://github.com/turbolinks/turbolinks&lt;/a&gt; ，我这里就不重复文档的内容了。&lt;/p&gt;
&lt;h2 id="基本技巧"&gt;基本技巧&lt;/h2&gt;&lt;h3 id="避免巨无霸型的 css 和 js 文件"&gt;避免巨无霸型的 css 和 js 文件&lt;/h3&gt;
&lt;p&gt;因为 Turbolinks 的加载机制，导致使用者倾向于把所有的样式和脚本打包成一个巨无霸型的 css 和 js，这会严重影响首次加载。Turbolinks 是完全支持不同页面加载不同的 css 和 js。&lt;/p&gt;

&lt;p&gt;简单心理的项目中，采用了如下方式来自动判断和加载当前页面所需的样式和脚本：&lt;/p&gt;
&lt;pre class="highlight slim"&gt;&lt;code&gt;&lt;span class="c"&gt;/ 加载样式文件，如 pages#home 的 css 文件，存放在 app/assets/stylesheets/www/pages/home.sass&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"app/assets/stylesheets/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subdomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sass"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stylesheet_link_tag&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subdomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;/ 加载脚本文件，如 pages#home 的 js 文件，存放在 app/assets/javascripts/www/pages/home.coffee&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"app/assets/javascripts/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subdomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.coffee"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;javascript_include_tag&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subdomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="简化页面加载事件"&gt;简化页面加载事件&lt;/h3&gt;
&lt;p&gt;因为 Turbolinks 的特殊加载机制，我们经常需要手动注册和注销事件。在简单心理，我们通过以下方式来简化这部分的代码：&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;_page_loaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="nx"&gt;_page_unload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="nx"&gt;_page_unload_once&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="c1"&gt;# 网页加载时执行&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$loaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;_page_loaded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 离开网页时执行&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$unload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;_page_unload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 离开网页时执行，且执行一次&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$unload_once&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;_page_unload_once&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 下面代码是以上接口的实现&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt; &lt;span class="s"&gt;'turbolinks:load'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;_page_loaded&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt; &lt;span class="s"&gt;'turbolinks:before-visit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;_page_unload_once&lt;/span&gt;
  &lt;span class="nx"&gt;_page_unload_once&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;_page_unload&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt; &lt;span class="s"&gt;'beforeunload'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;_page_unload_once&lt;/span&gt;
  &lt;span class="nx"&gt;_page_unload_once&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;_page_unload&lt;/span&gt;

  &lt;span class="no"&gt;null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="兼容 Vue.js 1.x"&gt;兼容 Vue.js 1.x&lt;/h3&gt;
&lt;p&gt;当一个页面的交互越来越复杂时，就需要用如 Vue.js 之类的框架，来简化交互的代码，但 Turbolinks 在缓存页面时，不会缓存 dom 里绑定的 events。当用户返回一个使用了 Vue 组件的页面时，这些组件的交互就都无法失效了。&lt;/p&gt;

&lt;p&gt;我们的解决思路是在页面离开时，缓存 Vue 组件的数据，并注销组件。当返回时，再重新渲染组件，并注入之前缓存的数据。&lt;/p&gt;

&lt;p&gt;另外要注意的是，Turbolinks 也会记住当前页面的滚动位置，记录在 &lt;code&gt;Turbolinks.controller.getCurrentRestorationData().scrollPosition&lt;/code&gt; 中，因此如果你的组件是一个长长的列表，且是异步加载的话，需要在加载前，先手动缓存这个位置（因为页面返回后，Turbolinks 会自动刷新记录值），待列表数据加载和渲染完成后，再将页面滚动到缓存的位置。&lt;/p&gt;

&lt;p&gt;具体实现如下：（因为我们现在不再继续使用 Vue.js，因此只给出 1.x 版本的实现方案）&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;vm_caches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nx"&gt;cache_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'raw'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;isnt&lt;/span&gt; &lt;span class="s"&gt;'undefined'&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'$data'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;is&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;
        &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;raw&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;
  &lt;span class="nx"&gt;cache&lt;/span&gt;

&lt;span class="nx"&gt;cache_vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$children&lt;/span&gt;
    &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;is&lt;/span&gt; &lt;span class="s"&gt;'undefined'&lt;/span&gt;
    &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cache_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;cache_vm&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;

&lt;span class="nx"&gt;$loaded&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;
    &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'body'&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt; &lt;span class="s"&gt;'turbolinks:before-cache'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# $.id 是一个生成唯一 ID 的函数，大家可以自行实现&lt;/span&gt;
    &lt;span class="nx"&gt;vm_caches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cache_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outerHTML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&amp;gt;&amp;lt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" _cache_key=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&amp;lt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;cache_vm&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vm_caches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="na"&gt;children&lt;/span&gt;
    &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;$destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;define&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'props'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt; &lt;span class="s"&gt;'_cache_key'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'ready'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;originalReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ready&lt;/span&gt;
    &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;vm_caches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_cache_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;vm_caches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_cache_key&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;constructor.name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;vm_caches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;_cache_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;vm_caches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;_cache_key&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;
          &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;
      &lt;span class="nx"&gt;originalReady&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;_cache_key&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;vm_caches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;_cache_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;

  &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;component&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你有更多技巧，欢迎交流分享。&lt;/p&gt;
&lt;h3 id="硬广"&gt;硬广&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="/topics/32136" title=""&gt;[北京][东直门][25-35k] 简单心理招聘高级 Ruby 工程师&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Tue, 17 Jan 2017 16:35:06 +0800</pubDate>
      <link>https://ruby-china.org/topics/32153</link>
      <guid>https://ruby-china.org/topics/32153</guid>
    </item>
    <item>
      <title>[北京][2017-02-18] 北京 Rubyists 聚会 (地址改为当代 MOMA 倍格生态 B1)</title>
      <description>&lt;p&gt;过完春节后，北京的 Rubyist 们来聚一下吧！&lt;/p&gt;

&lt;p&gt;时间：2017-02-18 下午 2 点&lt;/p&gt;

&lt;p&gt;地点：东直门附近，当代 MOMA 倍格生态 B1（进入当代 MOMA 后可以询问保安或物业人员）&lt;/p&gt;

&lt;p&gt;倍格照片：
&lt;img src="https://l.ruby-china.com/photo/2017/d21a1aa089362b63b29eccfd50c4ba60.jpg!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="分享内容："&gt;分享内容：&lt;/h3&gt;
&lt;p&gt;《伪·编程心理学》- 朱峰&lt;/p&gt;

&lt;p&gt;《打造面向初创公司的 DevOps 体系》- Boris&lt;/p&gt;
&lt;h3 id="招聘信息汇总："&gt;招聘信息汇总：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ruby-china.org/topics/32136" title=""&gt;[北京][东直门] 简单心理招聘高级 Ruby 工程师 (30k 起)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruby-china.org/topics/32232" title=""&gt;[北京] 卡拉丁—Ruby 开发工程师 [15-20K]—实习生&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruby-china.org/topics/32244" title=""&gt;[北京] 北京 学院南路 上市公司 招聘 Ruby 工程师 1 名&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruby-china.org/topics/29507" title=""&gt;[北京] 来自新一代数据分析产品 GrowingIO 对 Ruby 工程师的邀请 (20K - 40K)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruby-china.org/topics/31726" title=""&gt;[北京] 大鱼自助游诚觅 Ruby 工程师 / 全栈工程师 2~3 名&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>zfben</author>
      <pubDate>Mon, 16 Jan 2017 10:59:18 +0800</pubDate>
      <link>https://ruby-china.org/topics/32137</link>
      <guid>https://ruby-china.org/topics/32137</guid>
    </item>
    <item>
      <title>[北京][东直门] 简单心理招聘高级 Ruby 工程师 (30k 起)</title>
      <description>&lt;p&gt;程序员鼓励喵镇楼&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/2cfbd22d7405b4bef7ffb6a78839bd8e.jpeg!large" title="" alt="程序员鼓励喵"&gt;&lt;/p&gt;
&lt;h2 id="关于简单心理"&gt;关于简单心理&lt;/h2&gt;
&lt;p&gt;简单心理在做国内心理健康服务领域的标杆。我们培养、监督、筛选数量有限的专业心理咨询师和相关领域的从业者、生产靠谱的心理服务产品，为有心理健康帮助需求的用户提供有偿服务。&lt;/p&gt;

&lt;p&gt;简单心理从上线的第一天起，就在真实地影响、和改变心理咨询这个行业。我们想要站在互联网的肩膀上，帮助更多专业的、符合职业伦理的从业者，在专业的约束和保护下，帮助每一个家庭和每一个个体。&lt;/p&gt;

&lt;p&gt;我们是有温度、有边界、守伦理的心理服务者。&lt;/p&gt;
&lt;h2 id="投资人"&gt;投资人&lt;/h2&gt;
&lt;p&gt;简单心理投资方为硅谷和国内一线 VC：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NEA&lt;/strong&gt; 是一家覆盖全球的 VC。自成立以来，管理总计 170 亿美元的基金，活跃于科技和医疗领域。所投公司中，已经有 200 家企业上市，另有 320 被收购。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;真格基金&lt;/strong&gt; 由著名天使投资人徐小平创办。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tim Draper&lt;/strong&gt; 硅谷投资机构 DFJ 创始人之一，先后投资过 Skype, Tesla。简单心理是 Tim Draper 继百度之后，投资的第二家中国企业。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;华创资本&lt;/strong&gt; 关注早期创业项目。&lt;/p&gt;

&lt;p&gt;2016 年初获得数百万美金 A 轮融资。&lt;/p&gt;
&lt;h2 id="企业福利"&gt;企业福利&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;舒适的办公环境&lt;/li&gt;
&lt;li&gt;提供 Macbook Pro&lt;/li&gt;
&lt;li&gt;五险一金&lt;/li&gt;
&lt;li&gt;做五休二，法定休期（偶尔也有额外假期，比如今年春节有 9 天假期）&lt;/li&gt;
&lt;li&gt;带薪年假&lt;/li&gt;
&lt;li&gt;不定期的内部分享（内容涵盖从咖啡的煮法到运营数据分析）&lt;/li&gt;
&lt;li&gt;免费午餐及各种水果零食和饮料&lt;/li&gt;
&lt;li&gt;心理咨询抵扣券&lt;/li&gt;
&lt;li&gt;宠物乱入（？）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="团队文化"&gt;团队文化&lt;/h2&gt;
&lt;p&gt;拥抱变化：客户端包括 Web、安卓、iOS、微信公众号/服务号/小程序；后端框架为 Ruby 2.4.0 + Rails 5.0.1，数据库为 Postgresql，数据仓库为 Hadoop。&lt;/p&gt;

&lt;p&gt;拥抱不同：社交恐惧？LGBT？都不是问题，我们接纳真实的你。&lt;/p&gt;
&lt;h2 id="招聘详情"&gt;招聘详情&lt;/h2&gt;
&lt;p&gt;职位：高级 Ruby 工程师（一名）&lt;/p&gt;

&lt;p&gt;工作地点：北京 · 东直门附近&lt;/p&gt;
&lt;h2 id="职位描述"&gt;职位描述&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;负责后端产品及部分 Web 端产品的开发、测试和维护&lt;/li&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;熟练掌握 Ruby 编程语言和 Ruby on Rails 框架以及&lt;strong&gt;五年及以上相关开发经验&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;有 Ruby 相关的开源项目&lt;/strong&gt;（可以是 fork 后修改的项目）&lt;/li&gt;
&lt;li&gt;掌握 Git 版本控制工具&lt;/li&gt;
&lt;li&gt;熟悉云计算平台的使用和部署方式（目前我们主要使用阿里云）&lt;/li&gt;
&lt;li&gt;掌握面向对象编程的概念和最佳实践&lt;/li&gt;
&lt;li&gt;掌握 Web 应用相关的标准和最佳实践&lt;/li&gt;
&lt;li&gt;扎实的计算机科学基础知识，熟悉操作系统，数据库、常见数据结构和算法，以及软件设计实践&lt;/li&gt;
&lt;li&gt;熟悉 Linux / Unix 操作系统&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;li&gt;熟悉心理学或心理咨询&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="应聘方式"&gt;应聘方式&lt;/h2&gt;
&lt;p&gt;请将你的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;简历&lt;/li&gt;
&lt;li&gt;联系方式&lt;/li&gt;
&lt;li&gt;期望薪资&lt;/li&gt;
&lt;li&gt;开源项目网址&lt;/li&gt;
&lt;li&gt;近期能够代表你编程水平的&lt;strong&gt;代码片段&lt;/strong&gt;（如果开源项目的代码不足以代表你的水平的话）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;发送至 &lt;a href="mailto:ben@jiandanxinli.com" title=""&gt;ben@jiandanxinli.com&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;我们收到后会在 24 小时内通过邮件、电话或你注明的联系方式联系你（节假日除外）。&lt;/p&gt;
&lt;h2 id="了解更多"&gt;了解更多&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.jiandanxinli.com/about" rel="nofollow" target="_blank" title=""&gt;关于简单心理&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://mp.weixin.qq.com/s/9N-rTGvoTNhtMsfi5AWePg" rel="nofollow" target="_blank" title=""&gt;（彩蛋）简单心理优秀员工的一天&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jiandanxinli.com/report2016" rel="nofollow" target="_blank" title=""&gt;2016 心理健康认知度与心理咨询行业调查报告&lt;/a&gt;&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Mon, 16 Jan 2017 10:41:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/32136</link>
      <guid>https://ruby-china.org/topics/32136</guid>
    </item>
    <item>
      <title>选择 jsonapi-resources 的理由</title>
      <description>&lt;p&gt;Rails 5 发布时的官方日志里，推荐了三种用于构建 API 的 gem，分别是 &lt;a href="https://github.com/rails/jbuilder" rel="nofollow" target="_blank" title=""&gt;Jbuilder&lt;/a&gt;、&lt;a href="https://github.com/rails-api/active_model_serializers" rel="nofollow" target="_blank" title=""&gt;Active Model Serializers&lt;/a&gt; 和 &lt;a href="https://github.com/cerebris/jsonapi-resources" rel="nofollow" target="_blank" title=""&gt;JSONAPI::Resources&lt;/a&gt;，其中前两种需要配合 rails-api 来使用，只有 jsonapi-resources 提供了 JSONAPI::ResourceController。&lt;/p&gt;

&lt;p&gt;我们最终选择了 jsonapi-resources 主要基于以下原因：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;它的 resource 语法与 active_model_serializers 相近，而我们之前使用的是 active_model_serializers&lt;/li&gt;
&lt;li&gt;active_model_serializers 不支持 abstract 特性，必须基于某个 model，而我们有些 resource 并非基于 model&lt;/li&gt;
&lt;li&gt;jsonapi-resources 内置了 fields 选项，可以方便的在请求端指定返回的字段，而不必返回全部字段&lt;/li&gt;
&lt;li&gt;返回的数据结构符合 &lt;a href="http://jsonapi.org/" rel="nofollow" target="_blank" title=""&gt;jsonapi 规范&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;JSONAPI::ResourceController 提供了 RESTful 的封装，可以省去不少代码&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;以上的原因只是对目前项目来说最需要的特性，更多特性可以去看官方文档。&lt;/p&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;jsonapi-resources： &lt;a href="https://github.com/cerebris/jsonapi-resources" rel="nofollow" target="_blank"&gt;https://github.com/cerebris/jsonapi-resources&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;jsonapi：&lt;a href="http://jsonapi.org" rel="nofollow" target="_blank"&gt;http://jsonapi.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;原文地址： &lt;a href="https://jiandanxinli.github.io/2016-07-30.html" rel="nofollow" target="_blank"&gt;https://jiandanxinli.github.io/2016-07-30.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Sat, 30 Jul 2016 16:46:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/30672</link>
      <guid>https://ruby-china.org/topics/30672</guid>
    </item>
    <item>
      <title>你们公司内部是怎么进行技术分享或培训的？</title>
      <description>&lt;p&gt;大多数程序员都是自己研究技术，有没有小型公司有内部的技术分享或者培训机制的？可以希望分享下这方面的经验吗？&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Sun, 27 Dec 2015 11:10:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/28541</link>
      <guid>https://ruby-china.org/topics/28541</guid>
    </item>
    <item>
      <title>Cucumber 如何测试需要获取页面内容的场景</title>
      <description>&lt;p&gt;如：&lt;/p&gt;

&lt;p&gt;我打开注册页面，输入手机号
我收到短信，读取其中的验证码
我在注册页面输入验证码，完成登陆&lt;/p&gt;

&lt;p&gt;其中短信和验证码都可以在脚本中读取，但验证码是随机生成的，不知道如何在 cucumber 里读取和输入？&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Fri, 27 Nov 2015 10:27:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/28211</link>
      <guid>https://ruby-china.org/topics/28211</guid>
    </item>
    <item>
      <title>[北京 · 中关村] [2015/11/21] 全栈工程师沙龙</title>
      <description>&lt;p&gt;来参加全栈工程师的沙龙吧！我们不争论编程语言的优劣，我们只探讨如何优雅得使用各种技术来达成商业目标！&lt;/p&gt;

&lt;p&gt;11/21 下午 3 点，在中关村立方庭，无论你是 Web 全栈，还是 App 全栈，一起来聊聊全栈的话题。&lt;/p&gt;

&lt;p&gt;沙龙安排：&lt;/p&gt;

&lt;p&gt;3:00 - 3:15 暖场，自我介绍 + 互相认识
3:15 - 3:45 基于 Ruby on Rails 的跨 Web 和 App 的全栈实践分享
3:45 - 5:00 自由交流（话题包括但不限于：全栈的团队管理、技术之外的全栈）&lt;/p&gt;

&lt;p&gt;报名链接： &lt;a href="http://www.huodongxing.com/event/5309247004400" rel="nofollow" target="_blank"&gt;http://www.huodongxing.com/event/5309247004400&lt;/a&gt;&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Thu, 19 Nov 2015 14:23:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/28110</link>
      <guid>https://ruby-china.org/topics/28110</guid>
    </item>
    <item>
      <title>2.5 个人如何开发一款跨终端的产品？[Ruby Tuesday 的分享]</title>
      <description>&lt;p&gt;Keynote 在这里（需要翻墙）： &lt;a href="https://speakerdeck.com/benz303/2-dot-5-ge-ren-ru-he-kai-fa-kuan-kua-zhong-duan-de-chan-pin" rel="nofollow" target="_blank"&gt;https://speakerdeck.com/benz303/2-dot-5-ge-ren-ru-he-kai-fa-kuan-kua-zhong-duan-de-chan-pin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;不看 Keynote 也没关系，我会具体说下我们公司（&lt;a href="https://www.jiandanxinli.com" rel="nofollow" target="_blank" title=""&gt;简单心理&lt;/a&gt;）如何在仅有 2.5 个人的情况下，基于 RoR 开发出了涵盖几乎全部常用终端的产品。&lt;/p&gt;
&lt;h2 id="2.5 个人？"&gt;2.5 个人？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1 个全栈（我 ^_^）&lt;/li&gt;
&lt;li&gt;1 个 Ruby 程序员&lt;/li&gt;
&lt;li&gt;0.5 个前端开发（产品经理兼职）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="跨终端？"&gt;跨终端？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;电脑：浏览器、微信 PC 版（PC 版微信支持微信登陆）&lt;/li&gt;
&lt;li&gt;平板：浏览器、App（Android &amp;amp; iOS）、微信&lt;/li&gt;
&lt;li&gt;手机：浏览器、App（Android &amp;amp; iOS）、微信&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这些终端不仅用于访问，还需要支持推送和支付：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;通知渠道：邮件、短信、微信、App 推送&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;尽可能利用 RoR 已有技术&lt;/li&gt;
&lt;li&gt;基于 User Agent 信息来区分具体终端&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="从 RoR 出发"&gt;从 RoR 出发&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 Turbolinks 优化网页加载体验&lt;/li&gt;
&lt;li&gt;不使用前端 MVC 框架加重工作量&lt;/li&gt;
&lt;li&gt;使用响应式设计 + 部分页面 Variant Response&lt;/li&gt;
&lt;li&gt;不针对各个终端单独制作页面&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="基于 browser 区分终端"&gt;基于 browser 区分终端&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;browser 的双重含义：浏览器 和 browser gem&lt;/li&gt;
&lt;li&gt;每个终端都有各自的 User Agent&lt;/li&gt;
&lt;li&gt;通过扩展 browser gem 来判断当前的终端类型&lt;/li&gt;
&lt;li&gt;通过打印终端类型到 body class 使得 CSS 可以针对性调整样式&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="具体步骤"&gt;具体步骤&lt;/h2&gt;&lt;h2 id="1. 使用并扩展 browser gem 来判断终端类型"&gt;1. 使用并扩展 &lt;a href="https://github.com/fnando/browser" rel="nofollow" target="_blank" title=""&gt;browser gem&lt;/a&gt; 来判断终端类型&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Browser&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NAMES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:smileback&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'SmileBack'&lt;/span&gt; &lt;span class="c1"&gt;# 我们 App 的自定义 User Agent 标识&lt;/span&gt;
&lt;span class="no"&gt;Browser&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NAMES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:wechat&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Wechat'&lt;/span&gt;
&lt;span class="no"&gt;Browser&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NAMES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:desktop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Desktop'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Browser&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Meta&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Smileback&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Base&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;meta&lt;/span&gt;
        &lt;span class="s1"&gt;'smileback'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;smileback?&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;Wechat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Base&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;meta&lt;/span&gt;
        &lt;span class="s1"&gt;'wechat'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wechat?&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;Desktop&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Base&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;meta&lt;/span&gt;
        &lt;span class="s1"&gt;'desktop'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;desktop?&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;module&lt;/span&gt; &lt;span class="nn"&gt;Consoles&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;smileback?&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/smileback/i&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;def&lt;/span&gt; &lt;span class="nf"&gt;wechat?&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/MicroMessenger/i&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;def&lt;/span&gt; &lt;span class="nf"&gt;desktop?&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mobile?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;wechat?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;smileback?&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="2. 在 html body class 里添加 browser 信息，方便 CSS 套用"&gt;2. 在 html body class 里添加 browser 信息，方便 CSS 套用&lt;/h2&gt;&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="no"&gt;Browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;ua: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_USER_AGENT'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- class 会输出如 chrome modern mac webkit desktop 或 iphone ios mobile modern other safari safari5 webkit --!&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;/* 默认的样式 */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.desktop&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;/* 桌面浏览器定制样式 */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.mobile&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;/* 手机浏览器定制样式 */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.wechat&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;/* 微信定制样式 */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="3. 使用 Variant Response 来针对部分区别大的页面做两套或多套 views"&gt;3. 使用 &lt;a href="http://api.rubyonrails.org/classes/ActionController/MimeResponds.html" rel="nofollow" target="_blank" title=""&gt;Variant Response&lt;/a&gt; 来针对部分区别大的页面做两套或多套 views&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# application_controller.rb&lt;/span&gt;

&lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:detect_browser&lt;/span&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;detect_browser&lt;/span&gt;
  &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:mobile&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;ua: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_USER_AGENT'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;mobile?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要拆分的页面，做成如下形式：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/views/pages/home.erb
app/views/pages/home.html+mobile.erb # 文件名格式为 响应格式+设备名
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="4. 添加 helper，方便复杂的情况下调用，比如支付"&gt;4. 添加 helper，方便复杂的情况下调用，比如支付&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# application_helper.rb&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;browser&lt;/span&gt;
  &lt;span class="vi"&gt;@_browser&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;ua: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_USER_AGENT'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight slim"&gt;&lt;code&gt;&lt;span class="c"&gt;/ 懒得转 erb 格式了，下面这段是 slim 格式的&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;smileback?&lt;/span&gt;
  &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"jdxlsmileback://recharges/#{resource.id}/pay"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;支付宝付款
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'银联付款'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pay_recharge_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unionpay: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'data-no-turbolink'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wechat?&lt;/span&gt;
  &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weixin_id&lt;/span&gt;
    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&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;id: &lt;/span&gt;&lt;span class="s1"&gt;'wepay'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'button'&lt;/span&gt;
    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'银联付款'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pay_recharge_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unionpay: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'data-no-turbolink'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="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="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'银联付款'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pay_recharge_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unionpay: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'data-no-turbolink'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'button'&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mobile?&lt;/span&gt;
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'支付宝付款'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pay_recharge_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;alipay: &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;class: &lt;/span&gt;&lt;span class="s1"&gt;'button'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'data-no-turbolink'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'银联付款'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pay_recharge_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unionpay: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'data-no-turbolink'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="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="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'支付宝付款'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pay_recharge_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;alipay: &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;class: &lt;/span&gt;&lt;span class="s1"&gt;'button'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'data-no-turbolink'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'微信支付'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pay_recharge_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;scan_wepay: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'银联付款'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pay_recharge_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unionpay: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'data-no-turbolink'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="其它经验"&gt;其它经验&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;iOS App 我们用 WKWebView 套的壳，WKWebView 比 UIWebView 性能更好些，但限制也更多些，具体可以 Google。&lt;/li&gt;
&lt;li&gt;Android App 我们用默认的 WebView，目前没发现更好的替代品。&lt;/li&gt;
&lt;li&gt;支付渠道之前我们是自己封装的，现在发现 &lt;a href="https://pingxx.com" rel="nofollow" target="_blank" title=""&gt;Ping++&lt;/a&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;p&gt;我们需要：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby 工程师 月薪 15k 起&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我们提供：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;最人性化的工作环境（老板及大部分员工都有心理学专业背景，程序员鼓励师弱爆了 &lt;img title=":smirk:" alt="😏" src="https://twemoji.ruby-china.com/2/svg/1f60f.svg" class="twemoji"&gt; ）&lt;/li&gt;
&lt;li&gt;非北京地区可远程工作（本部位于北京中关村）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;欢迎勾搭 &lt;a href="mailto:hr@jiandanxinli.com" title=""&gt;hr@jiandanxinli.com&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="休息下，看看养眼的照片吧（非 PS）"&gt;休息下，看看养眼的照片吧（非 PS）&lt;/h2&gt;
&lt;p&gt;女王大人（曾用名：煤球）及她的孩子们
&lt;img src="http://jdxl-img.b0.upaiyun.com/id_cards/f6c6fb9742d94eb1aa5f73eb3e8b15d1.jpg" title="" alt="猫"&gt;&lt;/p&gt;

&lt;p&gt;各种帅哥美女云集的活动
&lt;img src="http://jdxl-img.b0.upaiyun.com/id_cards/6a9656184f9a467eac8d7c7f5ab0d5e2.jpg" title="" alt="帅哥美女"&gt;&lt;/p&gt;

&lt;p&gt;了解更多我们公司的详情可以移步这里： &lt;a href="http://www.jiandanxinli.com/pages/37" rel="nofollow" target="_blank"&gt;http://www.jiandanxinli.com/pages/37&lt;/a&gt;&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Wed, 09 Sep 2015 07:56:42 +0800</pubDate>
      <link>https://ruby-china.org/topics/27248</link>
      <guid>https://ruby-china.org/topics/27248</guid>
    </item>
    <item>
      <title>公益组织 [简七读财] 招募 Ruby 工程师</title>
      <description>&lt;p&gt;目前项目主页： &lt;a href="http://www.douban.com/people/jane77tang/notes" rel="nofollow" target="_blank"&gt;http://www.douban.com/people/jane77tang/notes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;经过第一轮的志愿者招募，我们已经非常幸运的得到了很多人的帮助：&lt;/p&gt;

&lt;p&gt;正在帮我们搭建网站的技术组、视觉组；
帮我们回答各位疑问的专家组；
帮我们采访有趣理财故事的小记者组；
不断把我们推荐给最好朋友的小广播组；
还有 QQ 群里帮助维护秩序、通过验证、提供资源链接等的管理员组。&lt;/p&gt;

&lt;p&gt;每一天我们都感到惊喜，每次看到有小伙伴说“谢谢你们的分享”，我们都更喜欢现在在做的这件事情。&lt;/p&gt;

&lt;p&gt;如果你和我们一样，你希望成为我们的一员，欢迎你来加入我们：&lt;/p&gt;

&lt;p&gt;目前急需：&lt;/p&gt;

&lt;p&gt;精通保险的小伙伴，以及精通 Ruby 编程的小伙伴！&lt;/p&gt;

&lt;p&gt;路在前方，我们勇敢前行。&lt;/p&gt;

&lt;p&gt;加入我们，请发送邮件到 missjane7@vip.sina.com&lt;/p&gt;

&lt;p&gt;❤❤❤❤❤❤❤关于我们和我们的梦想 喵七（80 后）和简七（85 后），好朋友兼草根金融理财爱好者，发现身边太多朋友和同事辛苦工作却缺乏基础的金融理财知识，仅专注于工作薪水缺乏财务自由精神。发起背景：
我们曾经在公司内部成立员工理财团，发现通过每月的理财讲座可以帮助到同事实现更好的人生规划，提升家庭幸福指数。同时我们开始尝试用故事和简单的方式阐述金融理财知识，从 8 月初至今在豆瓣、大申发表了多篇理财入门级的帖子，得到广泛积极的反应。9 月 2 日开始推送微信平台 - 简七读财，到现在已累计到 3300 余人关注，好感人好鼓舞！在这个过程中，我们发现我们有帮助别人的力量，并且希望可以帮助到更多人。我们的梦想：
1.成立一个类似科学松鼠会的自由淘金会网站（在生活的大浪里我们一起来淘金，实现自己的财务自由梦想），并做定期的线下公益性分享和普法讲座。
2.做一个即时问答型 APP，召集志愿者和我们一起，随时回答大家的提问，手把手帮助大家走上金融理财成长之路。我们还刚刚开始，我们不知道未来能否成功，但我们愿意为了心中的梦想去努力奋斗，而且我们相信，只要专注于做自己热爱的事情，会有好事发生的。&lt;/p&gt;

&lt;p&gt;=====&lt;/p&gt;

&lt;p&gt;Ruby 程序员备注：&lt;/p&gt;

&lt;p&gt;目前准备招募 1～2 名 Ruby 程序员，全端工程师优先，需要有远程工作能力（所以地区不限）。由于是公益组织，所以没有任何报酬，所有人都是利用自己的业余时间。&lt;/p&gt;

&lt;p&gt;网站目前已经开发了一小部分，还未上线，主要采用 Rails 4.0+Postgresql 9.2。&lt;/p&gt;

&lt;p&gt;近期的开发内容主要是“知识堂”（简单的 CMS 系统）和“问答”（简化版的知乎），等 Web 开发告一段落后，开始开发手机端（手机端程序员已招募到）。&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Thu, 24 Oct 2013 20:31:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/15010</link>
      <guid>https://ruby-china.org/topics/15010</guid>
    </item>
    <item>
      <title>ok, glass</title>
      <description>&lt;p&gt;&lt;a href="http://jackwmorgan.com/ok-glass/" rel="nofollow" target="_blank"&gt;http://jackwmorgan.com/ok-glass/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;比 ok, google 酷多了，原来 google glass 的潜力那么大！&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Thu, 16 May 2013 14:20:12 +0800</pubDate>
      <link>https://ruby-china.org/topics/11028</link>
      <guid>https://ruby-china.org/topics/11028</guid>
    </item>
    <item>
      <title>新浪首页采用 Flat UI 了，你有什么想说的？</title>
      <description>&lt;p&gt;&lt;img src="https://pathakacdn-a.akamaihd.net/photos2/231521c2-b249-40fa-b686-50c53d6828a2/2x.jpg" title="" alt="新浪首页截图"&gt;&lt;/p&gt;

&lt;p&gt;曾经的反面教材现在要翻身了？！&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.sina.com.cn/" rel="nofollow" target="_blank"&gt;http://www.sina.com.cn/&lt;/a&gt;&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Mon, 01 Apr 2013 18:14:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/9904</link>
      <guid>https://ruby-china.org/topics/9904</guid>
    </item>
    <item>
      <title>[上海] 招聘中高级 Ruby 程序员</title>
      <description>&lt;p&gt;牛男网（&lt;a href="http://www.neonan.com" rel="nofollow" target="_blank"&gt;http://www.neonan.com&lt;/a&gt;）是一家针对国内男性市场的综合性网络公司，我们的口号是：做一个更好的男人！
如果你想在工作的同时，学习如何成为一个“更好”的男人，那我们将是你最佳的选择。&lt;/p&gt;

&lt;p&gt;工作地点：&lt;/p&gt;

&lt;p&gt;上海市静安区，江宁路与武定路交叉口。
轨道交通：地铁 2 号线南京西路站，7 号线昌平路站。&lt;/p&gt;

&lt;p&gt;职位描述：&lt;/p&gt;

&lt;p&gt;Ruby 程序员主要工作是开发和维护我们的网站和 APP 的服务器端。
根据应聘者能力的不同负责不同难度的工作。
我们的后端主要采用以下技术：Ruby on Rails，Mysql，Mongodb，Redis，Unicorn，Nginx。&lt;/p&gt;

&lt;p&gt;待遇和福利：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;根据实际工作能力给予 8k 及上不封顶的月薪。&lt;/li&gt;
&lt;li&gt;公司配备至少双显示器等硬件设备。&lt;/li&gt;
&lt;li&gt;免费的零食、饮料和按摩服务。&lt;/li&gt;
&lt;li&gt;自由上下班时间，并有免费晚餐提供。&lt;/li&gt;
&lt;li&gt;公司的各种娱乐项目。&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;热爱编程，热爱生活。&lt;/li&gt;
&lt;li&gt;熟悉 Ruby on Rails，并有自己的 Ruby on Rails 项目。（能够在线访问的请提供网址，不能的话请将源代码打包为简历附件）&lt;/li&gt;
&lt;li&gt;熟悉 Ubuntu 和 Git，并熟悉 Git 的代码提交流程。&lt;/li&gt;
&lt;li&gt;熟悉 Mysql、Mongodb、Redis 中至少一种数据库，并对另外两种有所了解。&lt;/li&gt;
&lt;li&gt;具备良好的代码书写规范，善于思考，能独立分析和解决问题。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;加分：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;有 Github 账户并参与过开源 Ruby 项目&lt;/li&gt;
&lt;li&gt;熟悉 sass、slim、haml、coffeescript 等前端技术&lt;/li&gt;
&lt;li&gt;同时掌握 php 或 java 等另外一门后端语言&lt;/li&gt;
&lt;li&gt;了解用户体验，可以提出和实施 UE 方面的改进&lt;/li&gt;
&lt;li&gt;了解 SEO 以及其他网络营销知识&lt;/li&gt;
&lt;li&gt;了解 CDN 等网络加速技术&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;有意者请发送简历和项目代码至 jimmy@neonan.com&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Sat, 16 Mar 2013 11:20:09 +0800</pubDate>
      <link>https://ruby-china.org/topics/9468</link>
      <guid>https://ruby-china.org/topics/9468</guid>
    </item>
    <item>
      <title>Google Reader 即将关闭，你有什么想说的？</title>
      <description>&lt;p&gt;我准备自己写个程序把 feed 导入到 evernote 里，对第三方工具彻底无爱了=。=&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Thu, 14 Mar 2013 08:17:02 +0800</pubDate>
      <link>https://ruby-china.org/topics/9399</link>
      <guid>https://ruby-china.org/topics/9399</guid>
    </item>
    <item>
      <title>升级到 Rails4.0 后发现没什么新特性可以用上=。=</title>
      <description>&lt;p&gt;简单的个人网站，数据库使用 mongoid，所以 AR 的新特性被无视了；Strong Parameters 对于小网站而言也没有用武之地；网站访问量低，没写缓存，所以缓存的新特性也没有用上。&lt;/p&gt;

&lt;p&gt;目前看下来似乎只有 Turbolinks 可以尝试下？&lt;/p&gt;

&lt;p&gt;各位有什么打算升级到 Rails4.0 后使用的新特性吗？&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Thu, 28 Feb 2013 12:13:56 +0800</pubDate>
      <link>https://ruby-china.org/topics/9005</link>
      <guid>https://ruby-china.org/topics/9005</guid>
    </item>
    <item>
      <title>有省市列表之类的 gem 吗？</title>
      <description>&lt;p&gt;最好是国内的中文省市列表&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Fri, 07 Dec 2012 11:45:30 +0800</pubDate>
      <link>https://ruby-china.org/topics/7382</link>
      <guid>https://ruby-china.org/topics/7382</guid>
    </item>
    <item>
      <title>controller rspec 中如何直接操作 session？</title>
      <description>&lt;p&gt;在 controller spec 中直接操作&lt;code&gt;session[:user_id]=1&lt;/code&gt;是无效的，controller 中打印 session 显示的是 not loaded&lt;/p&gt;

&lt;p&gt;有什么办法吗？&lt;/p&gt;</description>
      <author>zfben</author>
      <pubDate>Fri, 07 Dec 2012 10:12:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/7379</link>
      <guid>https://ruby-china.org/topics/7379</guid>
    </item>
  </channel>
</rss>
