Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

Commit

Permalink
adding support for loading through Inherited Resources - closes #23
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanb committed Sep 9, 2010
1 parent a5ff826 commit 4eee637
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 8 deletions.
1 change: 1 addition & 0 deletions lib/cancan.rb
Expand Up @@ -5,3 +5,4 @@
require 'cancan/active_record_additions'
require 'cancan/exceptions'
require 'cancan/query'
require 'cancan/inherited_resource'
14 changes: 11 additions & 3 deletions lib/cancan/controller_additions.rb
Expand Up @@ -12,7 +12,7 @@ module ClassMethods
# end
#
def load_and_authorize_resource(*args)
ControllerResource.add_before_filter(self, :load_and_authorize_resource, *args)
cancan_resource_class.add_before_filter(self, :load_and_authorize_resource, *args)
end

# Sets up a before filter which loads the model resource into an instance variable.
Expand Down Expand Up @@ -103,7 +103,7 @@ def load_and_authorize_resource(*args)
# load_resource :new => :build
#
def load_resource(*args)
ControllerResource.add_before_filter(self, :load_resource, *args)
cancan_resource_class.add_before_filter(self, :load_resource, *args)
end

# Sets up a before filter which authorizes the resource using the instance variable.
Expand Down Expand Up @@ -156,7 +156,7 @@ def load_resource(*args)
# Authorize conditions on this parent resource when instance isn't available.
#
def authorize_resource(*args)
ControllerResource.add_before_filter(self, :authorize_resource, *args)
cancan_resource_class.add_before_filter(self, :authorize_resource, *args)
end

# Add this to a controller to ensure it performs authorization through +authorized+! or +authorize_resource+ call.
Expand Down Expand Up @@ -190,6 +190,14 @@ def skip_authorization(*args)
controller.instance_variable_set(:@_authorized, true)
end
end

def cancan_resource_class
if ancestors.map(&:to_s).include? "InheritedResources::Actions"
InheritedResource
else
ControllerResource
end
end
end

def self.included(base)
Expand Down
21 changes: 16 additions & 5 deletions lib/cancan/controller_resource.rb
Expand Up @@ -26,10 +26,10 @@ def load_and_authorize_resource
end

def load_resource
if !resource_instance && (parent? || member_action?)
@controller.instance_variable_set("@#{instance_name}", load_resource_instance)
if parent? || member_action?
self.resource_instance ||= load_resource_instance
elsif load_collection?
@controller.instance_variable_set("@#{instance_name.to_s.pluralize}", load_collection)
self.collection_instance ||= load_collection
end
end

Expand All @@ -41,7 +41,7 @@ def parent?
@options.has_key?(:parent) ? @options[:parent] : @name && @name != name_from_controller.to_sym
end

private
protected

def load_resource_instance
if !parent? && new_actions.include?(@params[:action].to_sym)
Expand All @@ -52,7 +52,6 @@ def load_resource_instance
end

def load_collection?
!parent? && collection_actions.include?(@params[:action].to_sym) &&
resource_base.respond_to?(:accessible_by) &&
!@controller.current_ability.has_block?(authorization_action, resource_class)
end
Expand Down Expand Up @@ -110,10 +109,22 @@ def resource_class_with_parent
parent_resource ? {parent_resource => resource_class} : resource_class
end

def resource_instance=(instance)
@controller.instance_variable_set("@#{instance_name}", instance)
end

def resource_instance
@controller.instance_variable_get("@#{instance_name}")
end

def collection_instance=(instance)
@controller.instance_variable_set("@#{instance_name.to_s.pluralize}", instance)
end

def collection_instance
@controller.instance_variable_get("@#{instance_name.to_s.pluralize}")
end

# The object that methods (such as "find", "new" or "build") are called on.
# If the :through option is passed it will go through an association on that instance.
# If the :singleton option is passed it won't use the association because it needs to be handled later.
Expand Down
18 changes: 18 additions & 0 deletions lib/cancan/inherited_resource.rb
@@ -0,0 +1,18 @@
module CanCan
# For use with Inherited Resources
class InheritedResource < ControllerResource # :nodoc:
def load_resource_instance
if parent?
@controller.parent
elsif new_actions.include? @params[:action].to_sym
@controller.build_resource
else
@controller.resource
end
end

def resource_base
@controller.end_of_association_chain
end
end
end
9 changes: 9 additions & 0 deletions spec/cancan/controller_additions_spec.rb
Expand Up @@ -74,4 +74,13 @@
@controller_class.check_authorization(:some_options)
}.should_not raise_error(CanCan::AuthorizationNotPerformed)
end

it "cancan_resource_class should be ControllerResource by default" do
@controller.class.cancan_resource_class.should == CanCan::ControllerResource
end

it "cancan_resource_class should be InheritedResource when class includes InheritedResources::Actions" do
stub(@controller.class).ancestors { ["InheritedResources::Actions"] }
@controller.class.cancan_resource_class.should == CanCan::InheritedResource
end
end
40 changes: 40 additions & 0 deletions spec/cancan/inherited_resource_spec.rb
@@ -0,0 +1,40 @@
require "spec_helper"

describe CanCan::InheritedResource do
before(:each) do
@params = HashWithIndifferentAccess.new(:controller => "projects")
@controller = Object.new # simple stub for now
@ability = Ability.new(nil)
stub(@controller).params { @params }
stub(@controller).current_ability { @ability }
end

it "show should load resource through @controller.resource" do
@params[:action] = "show"
stub(@controller).resource { :project_resource }
CanCan::InheritedResource.new(@controller).load_resource
@controller.instance_variable_get(:@project).should == :project_resource
end

it "new should load through @controller.build_resource" do
@params[:action] = "new"
stub(@controller).build_resource { :project_resource }
CanCan::InheritedResource.new(@controller).load_resource
@controller.instance_variable_get(:@project).should == :project_resource
end

it "index should load through @controller.parent when parent" do
@params[:action] = "index"
stub(@controller).parent { :project_resource }
CanCan::InheritedResource.new(@controller, :parent => true).load_resource
@controller.instance_variable_get(:@project).should == :project_resource
end

it "index should load through @controller.end_of_association_chain" do
@params[:action] = "index"
stub(Project).accessible_by(@ability) { :projects }
stub(@controller).end_of_association_chain { Project }
CanCan::InheritedResource.new(@controller).load_resource
@controller.instance_variable_get(:@projects).should == :projects
end
end

0 comments on commit 4eee637

Please sign in to comment.