Permalink
Browse files

Create gh-pages branch via GitHub

  • Loading branch information...
1 parent 9c4e034 commit 036aaf8d3aa586d932402c958b5a254de7b25108 @jnunemaker committed Apr 11, 2013
Showing with 64 additions and 70 deletions.
  1. +63 −69 index.html
  2. +1 −1 params.json
View
132 index.html
@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Canable by jnunemaker</title>
-
+
<link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
@@ -17,15 +17,22 @@
<header>
<h1>Canable</h1>
<p>Simple Ruby authorization system.</p>
+
<p class="view"><a href="https://github.com/jnunemaker/canable">View the Project on GitHub <small>jnunemaker/canable</small></a></p>
+
+
<ul>
<li><a href="https://github.com/jnunemaker/canable/zipball/master">Download <strong>ZIP File</strong></a></li>
<li><a href="https://github.com/jnunemaker/canable/tarball/master">Download <strong>TAR Ball</strong></a></li>
- <li><a href="https://github.com/jnunemaker/canable">Fork On <strong>GitHub</strong></a></li>
+ <li><a href="https://github.com/jnunemaker/canable">View On <strong>GitHub</strong></a></li>
</ul>
</header>
<section>
- <h2>Install</h2>
+ <h1>Canable</h1>
+
+<p>Simple Ruby authorization system.</p>
+
+<h2>Install</h2>
<pre><code>gem install canable
</code></pre>
@@ -34,38 +41,31 @@
<p>Whatever class you want all permissions to run through should include Canable::Cans.</p>
-<div class="highlight">
-<pre><span class="k">class</span> <span class="nc">User</span>
- <span class="kp">include</span> <span class="no">MongoMapper</span><span class="o">::</span><span class="no">Document</span>
- <span class="kp">include</span> <span class="no">Canable</span><span class="o">::</span><span class="no">Cans</span>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">User</span>
+ <span class="kp">include</span> <span class="ss">MongoMapper</span><span class="p">:</span><span class="ss">:Document</span>
+ <span class="kp">include</span> <span class="ss">Canable</span><span class="p">:</span><span class="ss">:Cans</span>
<span class="k">end</span>
-</pre>
-</div>
-
+</pre></div>
<p>This means that an instance of a user automatically gets can methods for the default REST actions: <code>can_view?(resource)</code>, <code>can_create?(resource)</code>, <code>can_update?(resource)</code>, <code>can_destroy?(resource)</code>.</p>
<h2>Ables</h2>
<p>Each of the can methods simply calls the related "able" method (viewable, creatable, updatable, destroyable) for the action (view, create, update, delete). Canable comes with defaults for this methods that you can then override as makes sense for your permissions.</p>
-<div class="highlight">
-<pre><span class="k">class</span> <span class="nc">Article</span>
- <span class="kp">include</span> <span class="no">MongoMapper</span><span class="o">::</span><span class="no">Document</span>
- <span class="kp">include</span> <span class="no">Canable</span><span class="o">::</span><span class="no">Ables</span>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">Article</span>
+ <span class="kp">include</span> <span class="ss">MongoMapper</span><span class="p">:</span><span class="ss">:Document</span>
+ <span class="kp">include</span> <span class="ss">Canable</span><span class="p">:</span><span class="ss">:Ables</span>
<span class="k">end</span>
-</pre>
-</div>
-
+</pre></div>
<p>Including Canable::Ables adds the able methods to the class including it. In this instance, article now has <code>viewable_by?(user)</code>, <code>creatable_by?(user)</code>, <code>updatable_by?(user)</code> and <code>destroyable_by?(user)</code>.</p>
<p>Lets say an article can be viewed and created by anyone, but only updated or destroyed by the user that created the article. To do that, you could leave <code>viewable_by?</code> and <code>creatable_by?</code> alone as they default to true and just override the other methods.</p>
-<div class="highlight">
-<pre><span class="k">class</span> <span class="nc">Article</span>
- <span class="kp">include</span> <span class="no">MongoMapper</span><span class="o">::</span><span class="no">Document</span>
- <span class="kp">include</span> <span class="no">Canable</span><span class="o">::</span><span class="no">Ables</span>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">Article</span>
+ <span class="kp">include</span> <span class="ss">MongoMapper</span><span class="p">:</span><span class="ss">:Document</span>
+ <span class="kp">include</span> <span class="ss">Canable</span><span class="p">:</span><span class="ss">:Ables</span>
<span class="n">userstamps!</span> <span class="c1"># adds creator and updater</span>
<span class="k">def</span> <span class="nf">updatable_by?</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
@@ -76,14 +76,11 @@
<span class="n">updatable_by?</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
-</pre>
-</div>
-
+</pre></div>
-<p>Lets look at some sample code now:</p>
+<p>Let's look at some sample code now:</p>
-<div class="highlight">
-<pre><span class="n">john</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="ss">:name</span> <span class="o">=&gt;</span> <span class="s1">'John'</span><span class="p">)</span>
+<div class="highlight"><pre><span class="n">john</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="ss">:name</span> <span class="o">=&gt;</span> <span class="s1">'John'</span><span class="p">)</span>
<span class="n">steve</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="ss">:name</span> <span class="o">=&gt;</span> <span class="s1">'Steve'</span><span class="p">)</span>
<span class="n">ruby</span> <span class="o">=</span> <span class="no">Article</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:title</span> <span class="o">=&gt;</span> <span class="s1">'Ruby'</span><span class="p">)</span>
@@ -101,101 +98,98 @@
<span class="n">john</span><span class="o">.</span><span class="n">can_destroy?</span><span class="p">(</span><span class="n">ruby</span><span class="p">)</span> <span class="c1"># true</span>
<span class="n">steve</span><span class="o">.</span><span class="n">can_destroy?</span><span class="p">(</span><span class="n">ruby</span><span class="p">)</span> <span class="c1"># false</span>
-</pre>
-</div>
+</pre></div>
+<p>Now we can implement our permissions for each resource and then always check whether a user can or cannot do something. This makes it all really easy to test. In one common pattern, a single permission flag controls whether or not users can perform multiple administrator-specific operations. Canable can honor that flag with:</p>
-<p>Now we can implement our permissions for each resource and then always check whether a user can or cannot do something. This makes it all really easy to test. Next, how would you use this in the controller.</p>
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">writable_by?</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
+ <span class="n">user</span><span class="o">.</span><span class="n">can_do_anything?</span>
+<span class="k">end</span>
+<span class="n">alias_method</span> <span class="ss">:creatable_by?</span><span class="p">,</span> <span class="ss">:writable_by?</span>
+<span class="n">alias_method</span> <span class="ss">:updatable_by?</span><span class="p">,</span> <span class="ss">:writable_by?</span>
+<span class="n">alias_method</span> <span class="ss">:destroyable_by?</span><span class="p">,</span> <span class="ss">:writable_by?</span>
+</pre></div>
+
+<p>Next, how would you use this in the controller. </p>
<h2>Enforcers</h2>
-<div class="highlight">
-<pre><span class="k">class</span> <span class="nc">ApplicationController</span>
- <span class="kp">include</span> <span class="no">Canable</span><span class="o">::</span><span class="no">Enforcers</span>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">ApplicationController</span>
+ <span class="kp">include</span> <span class="ss">Canable</span><span class="p">:</span><span class="ss">:Enforcers</span>
<span class="k">end</span>
-</pre>
-</div>
-
+</pre></div>
<p>Including <code>Canable::Enforcers</code> adds an enforce permission method for each of the actions defined (by default view/create/update/destroy). It is the same thing as doing this for each Canable action:</p>
-<div class="highlight">
-<pre><span class="k">class</span> <span class="nc">ApplicationController</span>
- <span class="kp">include</span> <span class="no">Canable</span><span class="o">::</span><span class="no">Enforcers</span>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">ApplicationController</span>
+ <span class="kp">include</span> <span class="ss">Canable</span><span class="p">:</span><span class="ss">:Enforcers</span>
<span class="n">delegate</span> <span class="ss">:can_view?</span><span class="p">,</span> <span class="ss">:to</span> <span class="o">=&gt;</span> <span class="ss">:current_user</span>
<span class="n">helper_method</span> <span class="ss">:can_view?</span> <span class="c1"># so you can use it in your views</span>
<span class="n">hide_action</span> <span class="ss">:can_view?</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">enforce_view_permission</span><span class="p">(</span><span class="n">resource</span><span class="p">)</span>
- <span class="k">raise</span> <span class="no">Canable</span><span class="o">::</span><span class="no">Transgression</span> <span class="k">unless</span> <span class="n">can_view?</span><span class="p">(</span><span class="n">resource</span><span class="p">)</span>
+ <span class="k">raise</span> <span class="ss">Canable</span><span class="p">:</span><span class="ss">:Transgression</span> <span class="k">unless</span> <span class="n">can_view?</span><span class="p">(</span><span class="n">resource</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
-</pre>
-</div>
-
+</pre></div>
<p>Which means you can use it like this:</p>
-<div class="highlight">
-<pre><span class="k">class</span> <span class="nc">ArticlesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">ArticlesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
<span class="k">def</span> <span class="nf">show</span>
<span class="vi">@article</span> <span class="o">=</span> <span class="no">Article</span><span class="o">.</span><span class="n">find!</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="ss">:id</span><span class="o">]</span><span class="p">)</span>
<span class="n">enforce_view_permission</span><span class="p">(</span><span class="vi">@article</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
-</pre>
-</div>
+</pre></div>
+
+<p>If the user <code>can_view?</code> the article, all is well. If not, a <code>Canable::Transgression</code> is raised which you can decide how to handle (show 404, slap them on the wrist, etc.). For example:</p>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">ApplicationController</span> <span class="o">&lt;</span> <span class="ss">ActionController</span><span class="p">:</span><span class="ss">:Base</span>
+ <span class="n">rescue_from</span> <span class="ss">Canable</span><span class="p">:</span><span class="ss">:Transgression</span><span class="p">,</span> <span class="ss">:with</span> <span class="o">=&gt;</span> <span class="ss">:render_403</span>
-<p>If the user <code>can_view?</code> the article, all is well. If not, a <code>Canable::Transgression</code> is raised which you can decide how to handle (show 404, slap them on the wrist, etc.).</p>
+ <span class="kp">protected</span>
+ <span class="k">def</span> <span class="nf">render_403</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
+ <span class="c1"># notify normal exception handler(s) here</span>
+ <span class="n">render</span> <span class="ss">:status</span> <span class="o">=&gt;</span> <span class="mi">403</span>
+ <span class="k">end</span>
+</pre></div>
<h2>Adding Your Own Actions</h2>
<p>You can add your own actions like this:</p>
-<div class="highlight">
-<pre><span class="no">Canable</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="ss">:publish</span><span class="p">,</span> <span class="ss">:publishable</span><span class="p">)</span>
-</pre>
-</div>
-
+<div class="highlight"><pre><span class="no">Canable</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="ss">:publish</span><span class="p">,</span> <span class="ss">:publishable</span><span class="p">)</span>
+</pre></div>
<p>The first parameter is the can method (ie: <code>can_publish?</code>) and the second is the able method (ie: <code>publishable_by?</code>).</p>
<p>Ables can also be added as class methods. For example, to restrict access to an index action:</p>
-<div class="highlight">
-<pre><span class="no">Canable</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:indexable</span><span class="p">)</span>
-</pre>
-</div>
-
+<div class="highlight"><pre><span class="no">Canable</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:indexable</span><span class="p">)</span>
+</pre></div>
<p>Then enforce by passing the class instead of the instance:</p>
-<div class="highlight">
-<pre><span class="k">class</span> <span class="nc">ArticlesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">ArticlesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
<span class="k">def</span> <span class="nf">index</span>
<span class="vi">@articles</span> <span class="o">=</span> <span class="no">Article</span><span class="o">.</span><span class="n">all</span>
<span class="n">enforce_index_permission</span><span class="p">(</span><span class="no">Article</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
-</pre>
-</div>
-
+</pre></div>
<p>Then in the article model, add the able check as a class method:</p>
-<div class="highlight">
-<pre><span class="k">class</span> <span class="nc">Article</span>
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">Article</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">indexable_by?</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="o">!</span><span class="n">user</span><span class="o">.</span><span class="n">nil?</span>
<span class="k">end</span>
<span class="k">end</span>
-</pre>
-</div>
-
+</pre></div>
<h2>Review</h2>
@@ -213,7 +207,7 @@
<li>Send me a pull request. Bonus points for topic branches.</li>
</ul><h2>Copyright</h2>
-<p>Copyright (c) 2010 John Nunemaker. See <a href="https://github.com/jnunemaker/canable/blob/master/LICENSE">LICENSE</a> for details.</p>
+<p>Copyright (c) 2010 John Nunemaker. See LICENSE for details.</p>
</section>
<footer>
<p>This project is maintained by <a href="https://github.com/jnunemaker">jnunemaker</a></p>
View
2 params.json
@@ -1 +1 @@
-{"name":"Canable","body":"## Install\r\n\r\n```\r\ngem install canable\r\n```\r\n\r\n## Cans\r\n\r\nWhatever class you want all permissions to run through should include Canable::Cans.\r\n\r\n```ruby\r\nclass User\r\n include MongoMapper::Document\r\n include Canable::Cans\r\nend\r\n```\r\n\r\nThis means that an instance of a user automatically gets can methods for the default REST actions: `can_view?(resource)`, `can_create?(resource)`, `can_update?(resource)`, `can_destroy?(resource)`.\r\n\r\n## Ables\r\n\r\nEach of the can methods simply calls the related \"able\" method (viewable, creatable, updatable, destroyable) for the action (view, create, update, delete). Canable comes with defaults for this methods that you can then override as makes sense for your permissions.\r\n\r\n```ruby\r\nclass Article\r\n include MongoMapper::Document\r\n include Canable::Ables\r\nend\r\n```\r\n\r\nIncluding Canable::Ables adds the able methods to the class including it. In this instance, article now has `viewable_by?(user)`, `creatable_by?(user)`, `updatable_by?(user)` and `destroyable_by?(user)`.\r\n\r\nLets say an article can be viewed and created by anyone, but only updated or destroyed by the user that created the article. To do that, you could leave `viewable_by?` and `creatable_by?` alone as they default to true and just override the other methods.\r\n\r\n```ruby\r\nclass Article\r\n include MongoMapper::Document\r\n include Canable::Ables\r\n userstamps! # adds creator and updater\r\n\r\n def updatable_by?(user)\r\n creator == user\r\n end\r\n\r\n def destroyable_by?(user)\r\n updatable_by?(user)\r\n end\r\nend\r\n```\r\n\r\nLets look at some sample code now:\r\n\r\n```ruby\r\njohn = User.create(:name => 'John')\r\nsteve = User.create(:name => 'Steve')\r\n\r\nruby = Article.new(:title => 'Ruby')\r\njohn.can_create?(ruby) # true\r\nsteve.can_create?(ruby) # true\r\n\r\nruby.creator = john\r\nruby.save\r\n\r\njohn.can_view?(ruby) # true\r\nsteve.can_view?(ruby) # true\r\n\r\njohn.can_update?(ruby) # true\r\nsteve.can_update?(ruby) # false\r\n\r\njohn.can_destroy?(ruby) # true\r\nsteve.can_destroy?(ruby) # false\r\n```\r\n\r\nNow we can implement our permissions for each resource and then always check whether a user can or cannot do something. This makes it all really easy to test. Next, how would you use this in the controller.\r\n\r\n## Enforcers\r\n\r\n```ruby\r\nclass ApplicationController\r\n include Canable::Enforcers\r\nend\r\n```\r\n\r\nIncluding `Canable::Enforcers` adds an enforce permission method for each of the actions defined (by default view/create/update/destroy). It is the same thing as doing this for each Canable action:\r\n\r\n```ruby\r\nclass ApplicationController\r\n include Canable::Enforcers\r\n\r\n delegate :can_view?, :to => :current_user\r\n helper_method :can_view? # so you can use it in your views\r\n hide_action :can_view?\r\n\r\n private\r\n def enforce_view_permission(resource)\r\n raise Canable::Transgression unless can_view?(resource)\r\n end\r\nend\r\n```\r\n\r\nWhich means you can use it like this:\r\n\r\n```ruby\r\nclass ArticlesController < ApplicationController\r\n def show\r\n @article = Article.find!(params[:id])\r\n enforce_view_permission(@article)\r\n end\r\nend\r\n```\r\n\r\nIf the user `can_view?` the article, all is well. If not, a `Canable::Transgression` is raised which you can decide how to handle (show 404, slap them on the wrist, etc.).\r\n\r\n## Adding Your Own Actions\r\n\r\nYou can add your own actions like this:\r\n\r\n```ruby\r\nCanable.add(:publish, :publishable)\r\n```\r\n\r\nThe first parameter is the can method (ie: `can_publish?`) and the second is the able method (ie: `publishable_by?`).\r\n\r\nAbles can also be added as class methods. For example, to restrict access to an index action:\r\n\r\n```ruby\r\nCanable.add(:index, :indexable)\r\n```\r\n\r\nThen enforce by passing the class instead of the instance:\r\n\r\n```ruby\r\nclass ArticlesController < ApplicationController\r\n def index\r\n @articles = Article.all\r\n enforce_index_permission(Article)\r\n end\r\nend\r\n```\r\n\r\nThen in the article model, add the able check as a class method:\r\n\r\n```ruby\r\nclass Article\r\n # ...\r\n def self.indexable_by?(user)\r\n !user.nil?\r\n end\r\nend\r\n```\r\n\r\n## Review\r\n\r\nSo, lets review: cans go on user model, ables go on everything, you override ables in each model where you want to enforce permissions, and enforcers go after each time you find or initialize an object in a controller. Bing, bang, boom.\r\n\r\n## Contributing\r\n\r\n* Fork the project.\r\n* Make your feature addition or bug fix.\r\n* Add tests for it. This is important so I don't break it in a\r\n future version unintentionally.\r\n* Commit, do not mess with rakefile, version, or history.\r\n (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)\r\n* Send me a pull request. Bonus points for topic branches.\r\n\r\n## Copyright\r\n\r\nCopyright (c) 2010 John Nunemaker. See [LICENSE](https://github.com/jnunemaker/canable/blob/master/LICENSE) for details.\r\n","tagline":"Simple Ruby authorization system.","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}
+{"name":"Canable","tagline":"Simple Ruby authorization system.","body":"# Canable\r\n\r\nSimple Ruby authorization system.\r\n\r\n## Install\r\n\r\n```\r\ngem install canable\r\n```\r\n\r\n## Cans\r\n\r\nWhatever class you want all permissions to run through should include Canable::Cans.\r\n\r\n```ruby\r\nclass User\r\n include MongoMapper::Document\r\n include Canable::Cans\r\nend\r\n```\r\n\r\nThis means that an instance of a user automatically gets can methods for the default REST actions: `can_view?(resource)`, `can_create?(resource)`, `can_update?(resource)`, `can_destroy?(resource)`.\r\n\r\n## Ables\r\n\r\nEach of the can methods simply calls the related \"able\" method (viewable, creatable, updatable, destroyable) for the action (view, create, update, delete). Canable comes with defaults for this methods that you can then override as makes sense for your permissions.\r\n\r\n```ruby\r\nclass Article\r\n include MongoMapper::Document\r\n include Canable::Ables\r\nend\r\n```\r\n\r\nIncluding Canable::Ables adds the able methods to the class including it. In this instance, article now has `viewable_by?(user)`, `creatable_by?(user)`, `updatable_by?(user)` and `destroyable_by?(user)`.\r\n\r\nLets say an article can be viewed and created by anyone, but only updated or destroyed by the user that created the article. To do that, you could leave `viewable_by?` and `creatable_by?` alone as they default to true and just override the other methods.\r\n\r\n```ruby\r\nclass Article\r\n include MongoMapper::Document\r\n include Canable::Ables\r\n userstamps! # adds creator and updater\r\n\r\n def updatable_by?(user)\r\n creator == user\r\n end\r\n\r\n def destroyable_by?(user)\r\n updatable_by?(user)\r\n end\r\nend\r\n```\r\n\r\nLet's look at some sample code now:\r\n\r\n```ruby\r\njohn = User.create(:name => 'John')\r\nsteve = User.create(:name => 'Steve')\r\n\r\nruby = Article.new(:title => 'Ruby')\r\njohn.can_create?(ruby) # true\r\nsteve.can_create?(ruby) # true\r\n\r\nruby.creator = john\r\nruby.save\r\n\r\njohn.can_view?(ruby) # true\r\nsteve.can_view?(ruby) # true\r\n\r\njohn.can_update?(ruby) # true\r\nsteve.can_update?(ruby) # false\r\n\r\njohn.can_destroy?(ruby) # true\r\nsteve.can_destroy?(ruby) # false\r\n```\r\n\r\nNow we can implement our permissions for each resource and then always check whether a user can or cannot do something. This makes it all really easy to test. In one common pattern, a single permission flag controls whether or not users can perform multiple administrator-specific operations. Canable can honor that flag with:\r\n\r\n```ruby\r\ndef writable_by?(user)\r\n user.can_do_anything?\r\nend\r\nalias_method :creatable_by?, :writable_by?\r\nalias_method :updatable_by?, :writable_by?\r\nalias_method :destroyable_by?, :writable_by?\r\n```\r\n\r\nNext, how would you use this in the controller. \r\n\r\n## Enforcers\r\n\r\n```ruby\r\nclass ApplicationController\r\n include Canable::Enforcers\r\nend\r\n```\r\n\r\nIncluding `Canable::Enforcers` adds an enforce permission method for each of the actions defined (by default view/create/update/destroy). It is the same thing as doing this for each Canable action:\r\n\r\n```ruby\r\nclass ApplicationController\r\n include Canable::Enforcers\r\n\r\n delegate :can_view?, :to => :current_user\r\n helper_method :can_view? # so you can use it in your views\r\n hide_action :can_view?\r\n\r\n private\r\n def enforce_view_permission(resource)\r\n raise Canable::Transgression unless can_view?(resource)\r\n end\r\nend\r\n```\r\n\r\nWhich means you can use it like this:\r\n\r\n```ruby\r\nclass ArticlesController < ApplicationController\r\n def show\r\n @article = Article.find!(params[:id])\r\n enforce_view_permission(@article)\r\n end\r\nend\r\n```\r\n\r\nIf the user `can_view?` the article, all is well. If not, a `Canable::Transgression` is raised which you can decide how to handle (show 404, slap them on the wrist, etc.). For example:\r\n\r\n```ruby\r\nclass ApplicationController < ActionController::Base\r\n rescue_from Canable::Transgression, :with => :render_403\r\n\r\n protected\r\n def render_403(e)\r\n # notify normal exception handler(s) here\r\n render :status => 403\r\n end\r\n```\r\n\r\n## Adding Your Own Actions\r\n\r\nYou can add your own actions like this:\r\n\r\n```ruby\r\nCanable.add(:publish, :publishable)\r\n```\r\n\r\nThe first parameter is the can method (ie: `can_publish?`) and the second is the able method (ie: `publishable_by?`).\r\n\r\nAbles can also be added as class methods. For example, to restrict access to an index action:\r\n\r\n```ruby\r\nCanable.add(:index, :indexable)\r\n```\r\n\r\nThen enforce by passing the class instead of the instance:\r\n\r\n```ruby\r\nclass ArticlesController < ApplicationController\r\n def index\r\n @articles = Article.all\r\n enforce_index_permission(Article)\r\n end\r\nend\r\n```\r\n\r\nThen in the article model, add the able check as a class method:\r\n\r\n```ruby\r\nclass Article\r\n # ...\r\n def self.indexable_by?(user)\r\n !user.nil?\r\n end\r\nend\r\n```\r\n\r\n## Review\r\n\r\nSo, lets review: cans go on user model, ables go on everything, you override ables in each model where you want to enforce permissions, and enforcers go after each time you find or initialize an object in a controller. Bing, bang, boom.\r\n\r\n## Contributing\r\n\r\n* Fork the project.\r\n* Make your feature addition or bug fix.\r\n* Add tests for it. This is important so I don't break it in a\r\n future version unintentionally.\r\n* Commit, do not mess with rakefile, version, or history.\r\n (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)\r\n* Send me a pull request. Bonus points for topic branches.\r\n\r\n## Copyright\r\n\r\nCopyright (c) 2010 John Nunemaker. See LICENSE for details.\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}

0 comments on commit 036aaf8

Please sign in to comment.