Skip to content

Commit

Permalink
turning load and authorize resource methods into class methods which …
Browse files Browse the repository at this point in the history
…set up the before filter so they can accept additional arguments
  • Loading branch information
ryanb committed Dec 13, 2009
1 parent 43947c8 commit a5f9882
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 52 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rdoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
* BACKWARDS INCOMPATIBLE: turning load and authorize resource methods into class methods which set up the before filter so they can accept additional arguments.

0.2.1 (Nov 26, 2009)

* many internal refactorings - see issues #11 and #12
Expand Down
91 changes: 49 additions & 42 deletions lib/cancan/controller_additions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,56 @@ module CanCan
# This module is automatically included into all controllers.
# It also makes the "can?" and "cannot?" methods available to all views.
module ControllerAdditions
module ClassMethods
# Sets up a before filter which loads and authorizes the current resource. This accepts the
# same arguments as load_resource and authorize_resource. See those methods for details.
#
# class BooksController < ApplicationController
# load_and_authorize_resource
# end
#
def load_and_authorize_resource(*args)
before_filter { |c| ResourceAuthorization.new(c, c.params, *args).load_and_authorize_resource }
end

# Sets up a before filter which loads the appropriate model resource into an instance variable.
# For example, given an ArticlesController it will load the current article into the @article
# instance variable. It does this by either calling Article.find(params[:id]) or
# Article.new(params[:article]) depending upon the action. It does nothing for the "index"
# action.
#
# You would call this method directly on the controller class.
#
# class BooksController < ApplicationController
# load_resource
# end
#
# See load_and_authorize_resource to automatically authorize the resource too.
def load_resource(*args) # TODO add documentation for options which can be passed.
before_filter { |c| ResourceAuthorization.new(c, c.params, *args).load_resource }
end

# Sets up a before filter which authorizes the current resource using the instance variable.
# For example, if you have an ArticlesController it will check the @article instance variable
# and ensure the user can perform the current action on it. Under the hood it is doing
# something like the following.
#
# unauthorized! if cannot?(params[:action].to_sym, @article || Article)
#
# You would call this method directly on the controller class.
#
# class BooksController < ApplicationController
# authorize_resource
# end
#
# See load_and_authorize_resource to automatically load the resource too.
def authorize_resource(*args)
before_filter { |c| ResourceAuthorization.new(c, c.params, *args).authorize_resource }
end
end

def self.included(base)
base.extend ClassMethods
base.helper_method :can?, :cannot?
end

Expand Down Expand Up @@ -70,48 +119,6 @@ def can?(*args)
def cannot?(*args)
(@current_ability ||= current_ability).cannot?(*args)
end

# This method loads the appropriate model resource into an instance variable. For example,
# given an ArticlesController it will load the current article into the @article instance
# variable. It does this by either calling Article.find(params[:id]) or
# Article.new(params[:article]) depending upon the action. It does nothing for the "index"
# action.
#
# You would often use this as a before filter in the controller. See
# load_and_authorize_resource to handle authorization too.
#
# before_filter :load_resource
#
def load_resource
ResourceAuthorization.new(self, params).load_resource
end

# Authorizes the resource in the current instance variable. For example,
# if you have an ArticlesController it will check the @article instance variable
# and ensure the user can perform the current action on it.
# Under the hood it is doing something like the following.
#
# unauthorized! if cannot?(params[:action].to_sym, @article || Article)
#
# You would often use this as a before filter in the controller.
#
# before_filter :authorize_resource
#
# See load_and_authorize_resource to automatically load the resource too.
def authorize_resource
ResourceAuthorization.new(self, params).authorize_resource
end

# Calls load_resource to load the current resource model into an instance variable.
# Then calls authorize_resource to ensure the current user is authorized to access the page.
# You would often use this as a before filter in the controller.
#
# before_filter :load_and_authorize_resource
#
def load_and_authorize_resource
load_resource
authorize_resource
end
end
end

Expand Down
22 changes: 12 additions & 10 deletions spec/cancan/controller_additions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,21 @@
@controller.cannot?(:foo, :bar).should be_true
end

it "should load resource" do
mock.instance_of(CanCan::ResourceAuthorization).load_resource
@controller.load_resource
it "load_and_authorize_resource should setup a before filter which passes call to ResourceAuthorization" do
stub(CanCan::ResourceAuthorization).new(@controller, @controller.params, :foo => :bar).mock!.load_and_authorize_resource
mock(@controller_class).before_filter { |block| block.call(@controller) }
@controller_class.load_and_authorize_resource :foo => :bar
end

it "should authorize resource" do
mock.instance_of(CanCan::ResourceAuthorization).authorize_resource
@controller.authorize_resource
it "authorize_resource should setup a before filter which passes call to ResourceAuthorization" do
stub(CanCan::ResourceAuthorization).new(@controller, @controller.params, :foo => :bar).mock!.authorize_resource
mock(@controller_class).before_filter { |block| block.call(@controller) }
@controller_class.authorize_resource :foo => :bar
end

it "should load and authorize resource in one call through controller" do
mock(@controller).load_resource
mock(@controller).authorize_resource
@controller.load_and_authorize_resource
it "load_resource should setup a before filter which passes call to ResourceAuthorization" do
stub(CanCan::ResourceAuthorization).new(@controller, @controller.params, :foo => :bar).mock!.load_resource
mock(@controller_class).before_filter { |block| block.call(@controller) }
@controller_class.load_resource :foo => :bar
end
end
7 changes: 7 additions & 0 deletions spec/cancan/resource_authorization_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,11 @@
authorization.authorize_resource
}.should raise_error(CanCan::AccessDenied)
end

it "should call load_resource and authorize_resource for load_and_authorize_resource" do
authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "show")
mock(authorization).load_resource
mock(authorization).authorize_resource
authorization.load_and_authorize_resource
end
end

0 comments on commit a5f9882

Please sign in to comment.