<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>evenluo (罗亦文)</title>
    <link>https://ruby-china.org/evenluo</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>阿里云 OSS 全攻略</title>
      <description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;这是一篇在阿里云 OSS 使用过程中我的一些经验，希望分享给大家&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;首先你需要一个开通了 OSS 的账户或者是阿里云主账户分配给你的有 OSS 权限的一个子账户。本文的前提条件是假设你拥有足够操作 OSS 的权限。&lt;/p&gt;
&lt;h2 id="相关概念"&gt;相关概念&lt;/h2&gt;
&lt;p&gt;RAM: RAM (Resource Access Management) 是阿里云为客户提供的用户身份管理与访问控制服务。&lt;a href="https://help.aliyun.com/document_detail/28627.html" rel="nofollow" target="_blank" title=""&gt;相关资料&lt;/a&gt;
STS：Security Token Service，是为阿里云账号（或 RAM 用户）提供&lt;strong&gt;短期&lt;/strong&gt;访问权限管理的云服务。&lt;a href="https://help.aliyun.com/document_detail/28756.html" rel="nofollow" target="_blank" title=""&gt;相关资料&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="客户端直传模型"&gt;客户端直传模型&lt;/h2&gt;
&lt;p&gt;为了不让 app server 成为瓶颈，客户端直传模型应该是最经常使用到的模型，时序图如下图：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/74f17f7073c1a76609d71aafad747182.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这样，app server 只需要向云 oss 的 sts 服务器请求临时凭据，然后再上传完毕之后接受回调，或者根据客户端提供的信息自行确认即可。
公开读的 bucket 在使用中几乎没有难度，本文不做介绍，本文介绍的是&lt;strong&gt;需要额外授权的文件读取&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="服务端实现"&gt;服务端实现&lt;/h2&gt;
&lt;p&gt;首先，先引入&lt;a href="https://github.com/aliyun/aliyun-oss-ruby-sdk" rel="nofollow" target="_blank" title=""&gt;官方 gem&lt;/a&gt;，官方的 readme 里面已经有比较详细的用法了，建议先完整地阅读官方的 readme。&lt;/p&gt;

&lt;p&gt;基本上一个项目可能一个 ram 账户就已经足够了，可以把生成 sts client 以单例的方式提取出来，示例代码&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;## sts_manager.rb&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'aliyun/sts'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'qiniu'&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Oss&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StsManager&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Singleton&lt;/span&gt;

    &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:sts_client&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
      &lt;span class="vi"&gt;@sts_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;STS&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&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;access_key_id: &lt;/span&gt;&lt;span class="no"&gt;BourneSetting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aliyun_oss_client_ak_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                        &lt;span class="ss"&gt;access_key_secret: &lt;/span&gt;&lt;span class="no"&gt;BourneSetting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aliyun_oss_client_ak_secret&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;在我的项目里，我把 aliyun 的 ak id 和 secret 都放到了 settinglogic 的设置中，并 ignore 掉&lt;/p&gt;

&lt;p&gt;有了 sts client 之后，就可以依据特定的条件办法 sts token 了。阿里云用一套 policy 来表征对某个资源的操作权限，其实这是一个很复杂的列表，当然跟 aws 很像，我也不说为什么了。policy 限定这个要产生的 token 对什么资源有着什么样的操作权限，你甚至还能指定其他一些条件 (condition)，但是这套规则在阿里云的文档里面比较分散，有种很混乱的感觉。大家可以重点参考&lt;a href="https://help.aliyun.com/document_detail/31867.html" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt;，&lt;a href="https://help.aliyun.com/knowledge_list/39711.html" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt; ，这里还有&lt;a href="http://oss-demo.aliyuncs.com/ram-policy-editor/?spm=5176.doc31867.2.19.etZLKE" rel="nofollow" target="_blank" title=""&gt;图形化的帮助页面&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这里我们假设一个示例代码&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;## sts_manager.rb&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;grant_write_credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"assets/user-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.png"&lt;/span&gt;
      &lt;span class="n"&gt;resource_description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"acs:oss:*:*:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;BourneSetting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aliyun_assets_bucket&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;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

      &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;STS&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
      &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'oss:PutObject'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'oss:AbortMultipartUpload'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;resource_description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;session_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;BourneSetting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;app_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;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-signature-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@sts_client.assume_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;BourneSetting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aliyun_arm_arn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在示例中，我们根据自己的业务逻辑生成了一个 key，这个你可以认为是在 bucket 上的一个路径（本质上只是模拟目录的一个做法），这里我们把上传的权限给定了这个 key，这个 key 不一定要详细到全路径，也可以使用类似于"assets/user-1/*"这样的方式表示以这个为前缀的 key 都有权上传。这个跟业务逻辑相关，但是需要注意的是：&lt;strong&gt;如果这个 key 上已经有文件，再次上传到这个 key 会直接覆盖这个文件&lt;/strong&gt;，如果你的业务不允许这样的事情发生，那么最好有更为严格的 key 控制。&lt;/p&gt;

&lt;p&gt;另外 session_name 大部分人也不知道是干什么的，这个我问过他们的支持，说这个 session_name 以后会作为审计的功能，现在暂时还没有用到，大家可以按照自己的逻辑设定。&lt;/p&gt;

&lt;p&gt;这样我们就会从 sts 服务器获得一个&lt;a href="http://www.rubydoc.info/gems/aliyun-sdk/Aliyun/STS/Token" rel="nofollow" target="_blank" title=""&gt;sts token&lt;/a&gt;，里面包含 access_key_id, access_key_secret, security_token, expiration, session_name，&lt;strong&gt;这些字段全部都有用&lt;/strong&gt;，这样你就可以把这个 token 和相关信息（bucket，key）返回给客户端，客户端就能开始使用了。&lt;/p&gt;
&lt;h2 id="客户端实现"&gt;客户端实现&lt;/h2&gt;
&lt;p&gt;客户端其实是可以任何形式，这里我们可以用 ruby sdk 作为客户端来测试一下&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;user_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;OSS&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&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;endpoint: &lt;/span&gt;&lt;span class="no"&gt;BourneSetting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aliyun_oss_hangzhou_endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                      &lt;span class="ss"&gt;access_key_id: &lt;/span&gt;&lt;span class="s2"&gt;"access_key_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                      &lt;span class="ss"&gt;access_key_secret: &lt;/span&gt;&lt;span class="s2"&gt;"access_key_secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                      &lt;span class="ss"&gt;sts_token: &lt;/span&gt;&lt;span class="s2"&gt;"sts_token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_bucket&lt;/span&gt; &lt;span class="s2"&gt;"bucket"&lt;/span&gt;
&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object&lt;/span&gt; &lt;span class="s2"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;file: &lt;/span&gt;&lt;span class="s2"&gt;"local_path"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的 id，secret，sts token，bucket 和 key 都来自于服务端，如果你的 policy 没错的话，那么你现在应该已经上传了&lt;/p&gt;
&lt;h2 id="cdn加速"&gt;cdn 加速&lt;/h2&gt;
&lt;p&gt;cdn 加速是一个很好的特性，便宜好用。cdn 默认支持 sts token 的鉴权方式，不需要做任何设置。&lt;/p&gt;
&lt;h2 id="坑"&gt;坑&lt;/h2&gt;
&lt;p&gt;这才是本文的主题。以上的东西都很简单，能满足大部分的需求。但是对于 oss 的需求不尽相同，在特殊需求出现的时候，可能就真的没法找文档了，只能工单一遍一遍你来我往，有时候还能刨出来 sdk 的坑。&lt;/p&gt;
&lt;h3 id="图片样式"&gt;图片样式&lt;/h3&gt;
&lt;p&gt;使用 oss 的有一个好处就是能够拥有对多媒体文件比如图片和视频一定的处理能力，比如图片样式：
&lt;img src="https://l.ruby-china.com/photo/2016/bcb126eaf129bdf72ccff6d7b2fb7ca2.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;但是你必须使用图片服务的域名（比如 bucket-name.img-cn-hangzhou.aliyuncs.com）作为 endpoint 来访问才可以得到这个样式。
如果你启用了禁止访问原图的设置：那么通过图片服务的域名你是无法访问原图的，但是如果你还是使用 oss 的域名作为 endpoint 来访问图片，却仍然是可以访问到的。。&lt;/p&gt;

&lt;p&gt;你可以变通的方式是，在编写 policy 的时候直接将样式写入 key 中，这样的话你生成的 sts token 就只能访问指定的样式了，比如这样的 key：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"key/to/test.jpg@!style"&lt;/span&gt;  &lt;span class="c1"&gt;#@!后面接样式的名称&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有时候你不想把这一大堆数据给客户端让客户端自己去访问文件，想直接生成一个签名过的链接给客户端就好，那么你可以调用&lt;strong&gt;bucket#object_url&lt;/strong&gt;方法直接生成一个签名链接给客户端，客户端在访问的时候云 oss 会自己做鉴权的。&lt;strong&gt;注意：&lt;/strong&gt;这个方法在 0.4.1 之前版本的 sdk 是不能生成正确的签名请求的，我也是踩过坑跟作者联系过，他很快就发布了 0.4.1 的版本。目前这个版本 policy 还不支持 condition 的操作，大家需要自己拼 json。&lt;/p&gt;
&lt;h3 id="自定义域名"&gt;自定义域名&lt;/h3&gt;
&lt;p&gt;现在 oss 可以有自定义域名，图片服务也可以有自定义域名，但是 cname 只能有一个，也就是说如果你想以一个自定义域名访问这两个服务域名是不可以的，还是只能通过不同的 endpoint 来达到访问的需求。&lt;/p&gt;

&lt;p&gt;这个解决方案最好是：把图片和文件分 bucket 存储。据说阿里云 oss 也觉得这两个域名会导致开发者傻傻分不清楚，准备进行改变。&lt;/p&gt;</description>
      <author>evenluo</author>
      <pubDate>Wed, 27 Jul 2016 17:22:54 +0800</pubDate>
      <link>https://ruby-china.org/topics/30643</link>
      <guid>https://ruby-china.org/topics/30643</guid>
    </item>
    <item>
      <title>极光推送的 gem 在设置时候的问题</title>
      <description>&lt;p&gt;最近在整合极光推送的时候，总是会遇到这个问题 &lt;a href="https://github.com/thoughtbot/factory_girl_rails/issues/215" rel="nofollow" target="_blank" title=""&gt;rspec#215&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;我还以为是人家 rspec 的问题呢，跑过去问了一下，后来发现是 jpush 的 gem 问题。感觉上应该和他们重写了类有关：&lt;a href="https://github.com/jpush/jpush-api-ruby-client/blob/master/lib/jpush/utils/helper.rb" rel="nofollow" target="_blank" title=""&gt;helper.rb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;而且这个问题会导致其他命令基本也用不了了，大家有没有解决的方法？&lt;/p&gt;</description>
      <author>evenluo</author>
      <pubDate>Thu, 14 Jul 2016 18:09:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/30529</link>
      <guid>https://ruby-china.org/topics/30529</guid>
    </item>
    <item>
      <title>[上海] 领孚科技诚聘中高级 Ruby 工程师 1 名 (15k-25k)</title>
      <description>&lt;h2 id="领孚是谁"&gt;领孚是谁&lt;/h2&gt;
&lt;p&gt;&lt;a href="linkfirms.com" title=""&gt;领孚科技&lt;/a&gt;创立于 2015 年末，是一家致力于企业线上公司治理的创业公司，公司已获得数百万投资。我们合伙人来自于国内知名律所，技术团队来自于 BAT。线下团队有非常丰富的公司治理经验，我们希望在我们产品的协助下，公司管理层、法律部门及其他相关人士能够实现无纸化、移动化、合规化地处理公司运营、管理及法律合规事务等事宜。团队的成员都是 90 后，人都很 nice，目前团队在杨浦区的一个孵化器内办公，交通很方便，工作环境很轻松。有着一群有热情，做事靠谱的同事们~&lt;/p&gt;
&lt;h2 id="工作待遇"&gt;工作待遇&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;工作时间：一周五天，&lt;strong&gt;基本没加过班&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;工作地点：上海市杨浦区创智天地&lt;/li&gt;
&lt;li&gt;薪资：15k-25k&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="招聘细则"&gt;招聘细则&lt;/h2&gt;
&lt;p&gt;您的主要职责：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;能独立的完成后端的开发工作。&lt;/li&gt;
&lt;li&gt;攻克项目的技术难关。&lt;/li&gt;
&lt;li&gt;有一定的服务器运维经验，可以成为 DevOps。&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 和 rails 框架。&lt;/li&gt;
&lt;li&gt;有着良好的代码书写习惯和较强的逻辑思维能力。&lt;/li&gt;
&lt;li&gt;有着良好的，循序的驱动测试习惯。&lt;/li&gt;
&lt;li&gt;熟练使用 shell 和 git，熟练使用 sublime，Vim，Atom 和 Emacs 中的一种。&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;有 github 开源贡献&lt;/li&gt;
&lt;li&gt;熟悉前端开发&lt;/li&gt;
&lt;li&gt;有稳定的无缝科学上网方式&lt;/li&gt;
&lt;li&gt;有云服务器，云 redis，云 rds 的使用经验&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="写在最后"&gt;写在最后&lt;/h2&gt;
&lt;p&gt;也许这就是能做成一件大事儿的机会。&lt;/p&gt;

&lt;p&gt;现在就发送简历！至 hr#linkfirms.com，或者访问&lt;a href="http://www.lagou.com/jobs/1865201.html" rel="nofollow" target="_blank" title=""&gt;领孚科技招聘&lt;/a&gt;，期待你的到来~&lt;/p&gt;</description>
      <author>evenluo</author>
      <pubDate>Wed, 01 Jun 2016 16:02:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/30183</link>
      <guid>https://ruby-china.org/topics/30183</guid>
    </item>
    <item>
      <title>sidekiq: Cannot define multiple 'included' blocks for a Concern</title>
      <description>&lt;p&gt;sidekiq 启动的时候报错 :&lt;/p&gt;

&lt;p&gt;Cannot define multiple 'included' blocks for a Concern&lt;/p&gt;

&lt;p&gt;看起来像是跟 sidekiq 的加载方式有关，找到了看起来最像的解决方案&lt;a href="https://www.stefanwienert.de/blog/2015/11/02/fix-sidekiq-loading-problem-cannot-define-multiple-included-blocks-for-a-concern/" rel="nofollow" target="_blank" title=""&gt;Fix Sidekiq loading problem: Cannot define multiple included blocks for a Concern&lt;/a&gt; 然而两个解决方法都未能解决。&lt;/p&gt;

&lt;p&gt;大家有没有遇到这个问题？如何解决的呢？&lt;/p&gt;</description>
      <author>evenluo</author>
      <pubDate>Fri, 22 Apr 2016 11:27:10 +0800</pubDate>
      <link>https://ruby-china.org/topics/29826</link>
      <guid>https://ruby-china.org/topics/29826</guid>
    </item>
    <item>
      <title>[已解决] 在 has_many, :through 的多对多关系中，如果获得中间表的 model 内容？</title>
      <description>&lt;p&gt;比如 Doctor 表和 Patient 表，关联表是 Appointment，其中 Appointment 表中有预约的额外信息，那我如果获得 appointment 呢。doctor.appointments 是不行的&lt;/p&gt;

&lt;p&gt;—————————————— 分割线 ————————————&lt;/p&gt;

&lt;p&gt;是可以的。。是自己的写法有误，抱歉&lt;/p&gt;</description>
      <author>evenluo</author>
      <pubDate>Tue, 05 Apr 2016 16:35:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/29546</link>
      <guid>https://ruby-china.org/topics/29546</guid>
    </item>
    <item>
      <title>Ruby 处理 PDF 的开源项目大家有了解么？</title>
      <description>&lt;p&gt;最近在做一个与 pdf 处理相关的事情，希望能用 ruby 处理 pdf，做到例如拼合，拆分，在 pdf 上添加图片生成新的 pdf 等功能。不知道各位有没有这方面的相关经验？&lt;/p&gt;</description>
      <author>evenluo</author>
      <pubDate>Tue, 01 Mar 2016 17:26:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/29172</link>
      <guid>https://ruby-china.org/topics/29172</guid>
    </item>
    <item>
      <title>[已解决] SendCloud 用 SMTP 配置发邮件总是 EOFError</title>
      <description>&lt;p&gt;development.rb 中：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config.action_mailer.smtp_settings = {
  :address        =&amp;gt; "smtpcloud.sohu.com",
  :port           =&amp;gt; 25,
  :authentication =&amp;gt; :login,
  :domain         =&amp;gt; "我的发信域名",
  :user_name      =&amp;gt; "我的api user",
  :password       =&amp;gt; "我的api key"
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其他写法是按照 ActionMailer 的 guide 来的。另外域名也已经验证通过了。&lt;/p&gt;

&lt;p&gt;返回如下：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UserMailer#welcome: processed outbound mail in 10.7ms

Sent mail to {收件地址} (1095.0ms)
Date: Mon, 18 Jan 2016 17:23:23 +0800
From: {发件地址}
To: {收件地址}
Message-ID: &amp;lt;569caf0b20afc_ba03ffaba3bc58c85776@matabuns-MacBook-Pro.local.mail&amp;gt;
Subject: Welcome
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: quoted-printable
...
EOFError (end of file reached):
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：个人信息已做处理。&lt;/p&gt;

&lt;p&gt;不知道哪里做得不对，能否指点一二？&lt;/p&gt;

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

&lt;p&gt;后来证明是所有的邮件必须都有对应的模板存在才可以。。我真是给这个错误提示跪了&lt;/p&gt;</description>
      <author>evenluo</author>
      <pubDate>Mon, 18 Jan 2016 17:30:12 +0800</pubDate>
      <link>https://ruby-china.org/topics/28768</link>
      <guid>https://ruby-china.org/topics/28768</guid>
    </item>
    <item>
      <title>mina 部署时遇到的问题</title>
      <description>&lt;p&gt;rails 新手，按照 mina 官方的教程来的，一切都还不错，直到出现了这个 &lt;/p&gt;

&lt;p&gt;'''
-----&amp;gt; Migrating database
$ RAILS_ENV="production" bundle exec rake db:migrate
rake aborted!
ActiveRecord::AdapterNotSpecified: 'production' database is not configured. Available: []
'''&lt;/p&gt;

&lt;p&gt;database.yml 的 production 节点如下：&lt;/p&gt;

&lt;p&gt;production:
  adapter: postgresql
  encoding: unicode
  database: app_production
  pool: 5
  host: 127.0.0.1
  username: deploy
  password: &lt;/p&gt;

&lt;p&gt;Google stackoverflow 查了好多，都没啥用。事实上在服务器上是存在 postgres 的，也是有 deploy 这个用户，同时也有 app_production 这个 database。
另外就是在本机上用 RAILS_ENV="production" bundle exec rake db:migrate 是成功了的，不知道我到底遇到了什么，麻烦各位指点一下。&lt;/p&gt;</description>
      <author>evenluo</author>
      <pubDate>Thu, 14 Jan 2016 16:15:18 +0800</pubDate>
      <link>https://ruby-china.org/topics/28731</link>
      <guid>https://ruby-china.org/topics/28731</guid>
    </item>
  </channel>
</rss>
