<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>icemark (Han)</title>
    <link>https://ruby-china.org/icemark</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>Keeping it Simple: Migrating to Pundit from CanCan 中文版</title>
      <description>&lt;p&gt;英文原版： &lt;a href="http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/" rel="nofollow" target="_blank"&gt;http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;过去几年我们大多数 Rails 项目的权限管理都使用了 CanCan。当项目升级到 Rails4 时，我发现 CanCan 不能兼容 strong parameters。有一些补丁的方法可以让 CanCan 跑起来，但是感觉不对味。当然 CanCan 也没有得到太多人的喜爱，而且 Cancan 的项目代码库上很多迹象都表明项目不够活跃，趋向于无人维护。&lt;/p&gt;

&lt;p&gt;我感觉是时候可以看看 Rails 权限管理方面有没有新的发现。&lt;/p&gt;

&lt;p&gt;大约一年前 Jonas Nicklas 发布了 Pundit，目的就是要创建更简单更少"魔法"的权限管理方案。&lt;/p&gt;

&lt;p&gt;这引起我强烈的共鸣！！！我不喜欢框架，特别是那些在背后做了太多或者太难理解工作的框架。我需要的是简单的，刚刚够用的东西，或者可以提供一个很好的壳，让我可以在上面添加我自己的东西，这也是非常棒的。&lt;/p&gt;

&lt;p&gt;我决定要尝试一下 Pundit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;迁移到 Pundit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;迁移到 Pundit 有以下几个步骤：
I. Policies and Policy Specs &lt;/p&gt;

&lt;p&gt;Pundit 从 Policy 对象中获取映射到 model 对象的认证规则。按照惯例，NotePolicy 保存的是 Note model 的规则。
我们需要手动把 Cancan 的 ability.rb 转为一个或者多个 Policies。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Styled for brevity...&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotePolicy&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationPolicy&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show?&lt;/span&gt;   &lt;span class="p"&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;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create?&lt;/span&gt; &lt;span class="p"&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;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update?&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;destroy?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# And a top-level policy for setting defaults.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationPolicy&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# User performing the action&lt;/span&gt;
              &lt;span class="ss"&gt;:record&lt;/span&gt; &lt;span class="c1"&gt;# Instance upon which action is performed&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;Pundit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NotAuthorizedError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Must be signed in."&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="vi"&gt;@record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&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;index?&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;def&lt;/span&gt; &lt;span class="nf"&gt;show?&lt;/span&gt;   &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;exists?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new?&lt;/span&gt;    &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;create?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                            &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create?&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;def&lt;/span&gt; &lt;span class="nf"&gt;edit?&lt;/span&gt;   &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;update?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                            &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update?&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;def&lt;/span&gt; &lt;span class="nf"&gt;destroy?&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;def&lt;/span&gt; &lt;span class="nf"&gt;scope&lt;/span&gt;
    &lt;span class="no"&gt;Pundit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;policy_scope!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&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="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这非常容易配合测试驱动开发&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;NotePolicy&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;NotePolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s2"&gt;"for a user"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:current_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;build_stubbed&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s2"&gt;"creating a new note"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;     &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;     &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s2"&gt;"with a note someone else created"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;build_stubbed&lt;/span&gt; &lt;span class="ss"&gt;:note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;     &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should_not&lt;/span&gt; &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:edit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should_not&lt;/span&gt; &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should_not&lt;/span&gt; &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:destroy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s2"&gt;"with a note that I created"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;build_stubbed&lt;/span&gt; &lt;span class="ss"&gt;:note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;     &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;     &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:edit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;     &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;     &lt;span class="n"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:destroy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tips:  推荐使用 FactoryGirl 的 build_stubbed .绝大多数情况下我们不需要持久化的实例，能不碰数据库就不碰。
&lt;strong&gt;II. Application Controller&lt;/strong&gt;
通过 ApplicationController 让 Pundit 在所有的 controllers 生效&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;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Pundit&lt;/span&gt;

  &lt;span class="c1"&gt;# Verify that controller actions are authorized. Optional, but good.&lt;/span&gt;
  &lt;span class="n"&gt;after_filter&lt;/span&gt; &lt;span class="ss"&gt;:verify_authorized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="ss"&gt;except: :index&lt;/span&gt;
  &lt;span class="n"&gt;after_filter&lt;/span&gt; &lt;span class="ss"&gt;:verify_policy_scoped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: :index&lt;/span&gt;

  &lt;span class="n"&gt;rescue_from&lt;/span&gt; &lt;span class="no"&gt;Pundit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NotAuthorizedError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;with: :user_not_authorized&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;user_not_authorized&lt;/span&gt;
    &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"You are not authorized to perform this action."&lt;/span&gt;
    &lt;span class="n"&gt;redirect_to&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;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Referer"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;root_path&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tips： 
通过第 5,6 行的 filters 来保证所有的 action 都进行认证，这和 CanCan 的 check_authorization 方法是类似的。这是可选的步骤，但是推荐加上&lt;/p&gt;

&lt;p&gt;------------- 中间部分跳过，直接到结论 ----&lt;/p&gt;

&lt;p&gt;我非常喜欢 Pundit，在我需要的场景中它都非常容易使用，也工作良好。Pundit 非常小，LOC 252，而 Cancan 是 1620，代码质量也很高，Code Climate 得分是 3.9.&lt;/p&gt;

&lt;p&gt;最后，我选择增加少量几行代码，而放弃隐藏的复杂性（又名“Magic” ）。我觉得这是一个合理的交换并让代码更具备可读性。在大多数情况下这是优点，对刚接触项目的新人就更为明显。Pundit 足够简单，任何开发人员都可以随时把它大卸八块来看看里面是咋回事。&lt;/p&gt;

&lt;p&gt;我的结论是：&lt;strong&gt;Pundit 胜出&lt;/strong&gt;！！！&lt;/p&gt;

&lt;p&gt;最后，我们也非常感谢创造了 CanCan 的 Ryan Bates ,CanCan 陪伴我们走过了这么多年，也是 Jonas 创造 Pundit 的起点。我们都非常幸运地成为这样一个充满活力的开放源代码社区的一部分。&lt;/p&gt;

&lt;p&gt;-- ruby-china 社区成员 icemark 冰痕 原创翻译 ----&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Fri, 11 Apr 2014 17:38:47 +0800</pubDate>
      <link>https://ruby-china.org/topics/18547</link>
      <guid>https://ruby-china.org/topics/18547</guid>
    </item>
    <item>
      <title>各个 Web 框架 解析 JSON 的评测结果</title>
      <description>&lt;p&gt;&lt;a href="http://www.techempower.com/benchmarks/#section=data-r8&amp;amp;hw=i7&amp;amp;test=json" rel="nofollow" target="_blank"&gt;http://www.techempower.com/benchmarks/#section=data-r8&amp;amp;hw=i7&amp;amp;test=json&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;分享各个 web 框架 解析 json 的评测结果&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Mon, 07 Apr 2014 10:41:03 +0800</pubDate>
      <link>https://ruby-china.org/topics/18446</link>
      <guid>https://ruby-china.org/topics/18446</guid>
    </item>
    <item>
      <title>出闲置全新 LEAP Motion </title>
      <description>&lt;p&gt;由于项目变动，多余出一个 Leap motion，只是拆开来验过货，没有使用过的，贴膜都没有拆，
淘宝上包邮价格是 515，现在 410 元包邮
图片：
&lt;a href="http://xiangce.baidu.com/picture/album/list/b47fa1b323f1f164ec754caca54185593b227584" rel="nofollow" target="_blank"&gt;http://xiangce.baidu.com/picture/album/list/b47fa1b323f1f164ec754caca54185593b227584&lt;/a&gt;&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Sun, 29 Dec 2013 15:19:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/16488</link>
      <guid>https://ruby-china.org/topics/16488</guid>
    </item>
    <item>
      <title>rmmseg-cpp 在 ruby 2.0 环境下遇到的问题和修复方法</title>
      <description>&lt;p&gt;问题 1：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;cannot&lt;/span&gt; &lt;span class="nb"&gt;load&lt;/span&gt; &lt;span class="n"&gt;such&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;jcode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修复方法：有两个文件需要改&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="sr"&gt;/usr/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rvm&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p247&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rmmseg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rmmseg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;
&lt;span class="sr"&gt;/usr/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rvm&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p247&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rmmseg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rmmseg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改法如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#require 'jcode'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'jcode'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;RUBY_VERSION&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'1.9'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;问题 2：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;NoMethodError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="sb"&gt;`length' for #&amp;lt;Enumerator: "high blue test":each_char&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修复方法：有一个文件需要改&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="sr"&gt;/usr/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rvm&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p247&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rmmseg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rmmseg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第 18 行改法如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# @chars = text.each_char&lt;/span&gt;
&lt;span class="vi"&gt;@chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;</description>
      <author>icemark</author>
      <pubDate>Fri, 25 Oct 2013 20:43:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/15038</link>
      <guid>https://ruby-china.org/topics/15038</guid>
    </item>
    <item>
      <title>有 gem 能对文章进行站内关键词自动添加链接吗</title>
      <description>&lt;p&gt;有 gem 能对文章进行站内关键词自动添加站内链接吗？&lt;/p&gt;

&lt;p&gt;这样的话 SEO 效果应会好些，
也能让用户在站内更方便找到相关内容&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Sat, 05 Oct 2013 10:16:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/14541</link>
      <guid>https://ruby-china.org/topics/14541</guid>
    </item>
    <item>
      <title>AVOS cloud 这个工具初看来不错 有用过的朋友吗？</title>
      <description>&lt;p&gt;&lt;a href="https://cn.avoscloud.com/" rel="nofollow" target="_blank"&gt;https://cn.avoscloud.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;数据库，API 访问 都做进去了，看起来还比较不错，降低自己部署服务器的麻烦和运营风险。&lt;/p&gt;

&lt;p&gt;准备试用一下，
如果有用过的朋友 可以分享一下经验就更好了，&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Wed, 18 Sep 2013 21:44:59 +0800</pubDate>
      <link>https://ruby-china.org/topics/14223</link>
      <guid>https://ruby-china.org/topics/14223</guid>
    </item>
    <item>
      <title>datatables 如何做做 I18n  ?</title>
      <description>&lt;p&gt;使用了  &lt;a href="http://asciicasts.com/episodes/340-datatables" rel="nofollow" target="_blank"&gt;http://asciicasts.com/episodes/340-datatables&lt;/a&gt;介绍的 datatables，
挺不错的，但是不知道如何做 I18n &lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Mon, 04 Feb 2013 12:24:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/8591</link>
      <guid>https://ruby-china.org/topics/8591</guid>
    </item>
    <item>
      <title>RubyConf Taiwan 的议题也挺好的</title>
      <description>&lt;p&gt;但是没有看到他们分享出来的 slide&lt;/p&gt;

&lt;p&gt;有看到的 xd 分享一下&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Mon, 10 Dec 2012 11:49:32 +0800</pubDate>
      <link>https://ruby-china.org/topics/7432</link>
      <guid>https://ruby-china.org/topics/7432</guid>
    </item>
    <item>
      <title>mruby everywhere -- Rubyconf 2012 上的演讲幻灯片</title>
      <description>&lt;p&gt;演讲幻灯片链接：&lt;a href="https://speakerdeck.com/matt_aimonetti/mmmm-dot-mruby-everywhere-and-revisiting-ruby" rel="nofollow" target="_blank"&gt;https://speakerdeck.com/matt_aimonetti/mmmm-dot-mruby-everywhere-and-revisiting-ruby&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;其他相关链接：
Mruby 在 android 上执行的例子：
 &lt;a href="http://www.oki-osk.jp/esc/mruby-oa/03.html" rel="nofollow" target="_blank"&gt;http://www.oki-osk.jp/esc/mruby-oa/03.html&lt;/a&gt; （日文版）&lt;/p&gt;

&lt;p&gt;用 mruby 开发 ios 游戏的例子 - MobiRuby  Game：
&lt;a href="https://itunes.apple.com/us/app/mobiruby-game/id548210182?mt=8" rel="nofollow" target="_blank"&gt;https://itunes.apple.com/us/app/mobiruby-game/id548210182?mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这是另外一篇 mruby 的介绍，里面有 C 调用 mruby 脚本执行的例子
&lt;a href="http://geekmonkey.org/articles/36-an-introduction-to-mini-ruby" rel="nofollow" target="_blank"&gt;http://geekmonkey.org/articles/36-an-introduction-to-mini-ruby&lt;/a&gt;&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Fri, 02 Nov 2012 22:23:42 +0800</pubDate>
      <link>https://ruby-china.org/topics/6491</link>
      <guid>https://ruby-china.org/topics/6491</guid>
    </item>
    <item>
      <title>以"京东充值漏洞"聊聊测试驱动开发</title>
      <description>&lt;p&gt;京东的充值漏洞 导致了巨大的损失，负责这个项目的工程师应该杯具了，我想他百分之 99.99999 没有实践测试驱动开发&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Fri, 02 Nov 2012 09:10:25 +0800</pubDate>
      <link>https://ruby-china.org/topics/6472</link>
      <guid>https://ruby-china.org/topics/6472</guid>
    </item>
    <item>
      <title>分享一个基于 rails 的开源众筹网站代码</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/danielweinmann/catarse" rel="nofollow" target="_blank"&gt;https://github.com/danielweinmann/catarse&lt;/a&gt;
在 github 上能找到的较为完整的众筹网站代码
基于 rails 3.2，每个月都有更新提交&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Sun, 23 Sep 2012 18:39:37 +0800</pubDate>
      <link>https://ruby-china.org/topics/5703</link>
      <guid>https://ruby-china.org/topics/5703</guid>
    </item>
    <item>
      <title>Thin 做 web 服务器凌晨换日记的时候 502</title>
      <description>&lt;p&gt;一个 API 项目 rails3.07+thin 运行了一年了，每个月都有一两次 502 发生在凌晨 log 换文件的时候：最后一条访问日记都是发生在 23:59:59 然后本来应该正常切换到新的 log 文件继续记录，但是却没有，直接 502 了。&lt;/p&gt;

&lt;p&gt;PS：日记也没有其他的错误信息。每天的访问日记条数在 90W 次左右（request-log-analyzer 的统计）&lt;/p&gt;

&lt;p&gt;有可能问题出在什么地方呢？&lt;/p&gt;

&lt;p&gt;日记配置文件如下：
&lt;code&gt;config.logger = Logger.new("#{Rails.root}/log/#{Rails.env}#{Date.today.to_s}.log", "daily")&lt;/code&gt;
&lt;code&gt;
Most requested
ThemesController#promote.XML    ┃ 833440 hits ┃ 83.9% ┃ ░░░░░░░░░░░░░░░░░░░░
ThemesController#stat.HTML      ┃  76869 hits ┃  7.7% ┃ ░░
&lt;/code&gt; 
&lt;code&gt;
Process blockers (&amp;gt; 1 sec duration)
ThemesController#promote.XML    ┃ 256 hits ┃ 94.1% ┃ ░
&lt;/code&gt; &lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Sun, 26 Aug 2012 10:01:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/5164</link>
      <guid>https://ruby-china.org/topics/5164</guid>
    </item>
    <item>
      <title>RGSS (ruby 游戏脚本) 的编译器问题</title>
      <description>&lt;p&gt;RGSS（Ruby Game Scripting System）是以 Ruby 语言为基础的游戏脚本语言
RGSS 的语法与 Ruby 完全相同。主要在图像的显示、音乐的演奏、游戏设计所需要之功能上作强化。（更多 RGSS 内容参见 &lt;a href="http://zh.wikipedia.org/wiki/RGSS" rel="nofollow" target="_blank"&gt;http://zh.wikipedia.org/wiki/RGSS&lt;/a&gt; ）&lt;/p&gt;

&lt;p&gt;但是好像找不到对应的独立编译器（只看到配套工具里面的动态链接库 dll 文件）&lt;/p&gt;

&lt;p&gt;假如 RGSS 的公司不提供独立编辑器，算不算侵犯了 ruby 的版权？&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Sun, 19 Aug 2012 15:24:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/5029</link>
      <guid>https://ruby-china.org/topics/5029</guid>
    </item>
    <item>
      <title>Grape 如何不重启 server 更新 api 接口</title>
      <description>&lt;p&gt;在用 Grape 写 API 接口的时候，每次更改都需要重启 server 才生效，
有没有方便一点的方法呢？&lt;/p&gt;

&lt;p&gt;在 mac 上 rails s 
停止用 control+z 还有杀进程，有点麻烦，
在 ubuntu 上 rails s 然后 ctrl+z 进程就自动关闭了 还方便很多&lt;/p&gt;

&lt;p&gt;mac 上有什么好方法能不重启 server 让 grape 生效吗？或者其他方便的方法能方便让修改的 API 马上可以用呢？&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Mon, 06 Aug 2012 12:20:24 +0800</pubDate>
      <link>https://ruby-china.org/topics/4760</link>
      <guid>https://ruby-china.org/topics/4760</guid>
    </item>
    <item>
      <title>ruby 脚本处理文件去重复行</title>
      <description>&lt;p&gt;大家如何写这个 ruby 脚本呢？
当然在 linux 上可以调用 shell 里面 uniq file 就可以完成任务了
如果是在 windows 执行 ruby 脚本如何写呢？
下面 google 得到的脚本 会把分行全部搞乱掉，&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# print file and remove duplicate, non-consecutive lines from a file (careful of memory!)&lt;/span&gt;
     &lt;span class="err"&gt;$&lt;/span&gt;  &lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="s1"&gt;'puts STDIN.readlines.sort.uniq!.to_s'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;txt&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;</description>
      <author>icemark</author>
      <pubDate>Wed, 02 May 2012 22:12:08 +0800</pubDate>
      <link>https://ruby-china.org/topics/3043</link>
      <guid>https://ruby-china.org/topics/3043</guid>
    </item>
    <item>
      <title>rails 如何做动态限时下载链接呢？</title>
      <description>&lt;p&gt;有些收费的下载链接需要动态链接，而且限时，过期就不能下载
有 gem 支持吗？&lt;/p&gt;

&lt;p&gt;或者大家有较好的设计方案呢？&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Mon, 30 Apr 2012 19:56:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/2998</link>
      <guid>https://ruby-china.org/topics/2998</guid>
    </item>
    <item>
      <title>产品被竞争对手恶意攻击崩溃</title>
      <description>&lt;p&gt;有一个大公司的产品恶意攻击我们的小团队的产品，导致 service 不断重启，
产品都是 android 系统的工具应用，会常驻后台，（这个公司有一款产品和我们正面竞争）
/**  Allows an application to restart other applications.           */&lt;br&gt;
"android.permission.RESTART_PACKAGES";&lt;br&gt;
对方的产品申请了可以关闭其他进程应用的权利，一般用户看不懂的话都会同意，已经保全了对方的应用，取证了证据。
请问大家遇到这种情况如何处理？&lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Mon, 02 Apr 2012 09:39:54 +0800</pubDate>
      <link>https://ruby-china.org/topics/2339</link>
      <guid>https://ruby-china.org/topics/2339</guid>
    </item>
    <item>
      <title>请教 Rails 和 纯 Redis  结合的的规范</title>
      <description>&lt;p&gt;因为有项目对数据即时反应要求较高，准备服务器端用纯 redis 做 消息队列和数据库
Rails 的 model 和 redis 交互方面大家有什么好点的代码规范呢？  &lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Wed, 21 Mar 2012 20:33:40 +0800</pubDate>
      <link>https://ruby-china.org/topics/2038</link>
      <guid>https://ruby-china.org/topics/2038</guid>
    </item>
    <item>
      <title>请教 view 里面的优化</title>
      <description>&lt;p&gt;产品拥有多个图片
列表展示的时候使用第一张图片作为缩略图
 image_tag product.previews.first.photo_url.to_s 
从 product 到 previews 到 first 
是不是也算把逻辑放到 view 里面了？导致 view 的解析慢了&lt;/p&gt;

&lt;p&gt;能够有更好的处理方法？  &lt;/p&gt;</description>
      <author>icemark</author>
      <pubDate>Sun, 18 Mar 2012 18:44:35 +0800</pubDate>
      <link>https://ruby-china.org/topics/1948</link>
      <guid>https://ruby-china.org/topics/1948</guid>
    </item>
  </channel>
</rss>
