Permalink
Browse files

Merge branch 'master' of https://github.com/ryanb/cancan

* 'master' of https://github.com/ryanb/cancan:
  Clarify readme for rails 2.3 users
  adding a .rbenv-version file
  Add check for Enumerable as condition value
  adding project status message to readme
  Just add singleton to description of authorize_resource
  Don't remove key-value from the subject hash we might want to use it again.
  adding travis-ci badge
  Pass forward :if and :unless options to the before filter. i.e:
  Fixed bug with params for actions that build new instances with namespaced models
  Use latest with_model gem

Conflicts:
	spec/cancan/controller_resource_spec.rb
  • Loading branch information...
2 parents 594aa21 + 8e46cca commit 1141dab17a4f6de5e153556a900ff75b11cd65fb @fuelxc fuelxc committed May 11, 2012
View
@@ -0,0 +1 @@
+1.8.7-p357
View
@@ -4,7 +4,7 @@ case ENV["MODEL_ADAPTER"]
when nil, "active_record"
gem "sqlite3"
gem "activerecord", '~> 3.0.9', :require => "active_record"
- gem "with_model", '~> 0.1.5'
+ gem "with_model", "~> 0.2.5"
gem "meta_where"
when "data_mapper"
gem "dm-core", "~> 1.0.2"
View
@@ -1,4 +1,4 @@
-= CanCan
+= CanCan {<img src="https://secure.travis-ci.org/ryanb/cancan.png" />}[http://travis-ci.org/ryanb/cancan]
Wiki[https://github.com/ryanb/cancan/wiki] | RDocs[http://rdoc.info/projects/ryanb/cancan] | Screencast[http://railscasts.com/episodes/192-authorization-with-cancan]
@@ -31,6 +31,15 @@ User permissions are defined in an +Ability+ class. CanCan 1.5 includes a Rails
rails g cancan:ability
+In Rails 2.3, just add a new class in `app/models/ability.rb` with the folowing contents:
+
+ class Ability
+ include CanCan::Ability
+
+ def initialize(user)
+ end
+ end
+
See {Defining Abilities}[https://github.com/ryanb/cancan/wiki/defining-abilities] for details.
@@ -99,6 +108,11 @@ This will raise an exception if authorization is not performed in an action. If
* {See more}[https://github.com/ryanb/cancan/wiki]
+== Project Status
+
+Unfortunately I have not had time to actively work on this project recently. If you find a critical issue where it does not work as documented please {ping me on twitter}[http://twitter.com/rbates] and I'll take a look.
+
+
== Questions or Problems?
If you have any issues with CanCan which you cannot find the solution to in the documentation[https://github.com/ryanb/cancan/wiki], please add an {issue on GitHub}[https://github.com/ryanb/cancan/issues] or fork the project and send a pull request.
@@ -151,6 +151,9 @@ def load_resource(*args)
# [:+except+]
# Does not apply before filter to given actions.
#
+ # [:+singleton+]
+ # Pass +true+ if this is a singleton resource through a +has_one+ association.
+ #
# [:+parent+]
# True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
# name is given which does not match the controller.
@@ -6,8 +6,8 @@ def self.add_before_filter(controller_class, method, *args)
options = args.extract_options!
resource_name = args.first
before_filter_method = options.delete(:prepend) ? :prepend_before_filter : :before_filter
- controller_class.send(before_filter_method, options.slice(:only, :except)) do |controller|
- controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except)).send(method)
+ controller_class.send(before_filter_method, options.slice(:only, :except, :if, :unless)) do |controller|
+ controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except, :if, :unless)).send(method)
end
end
@@ -82,7 +82,10 @@ def load_collection
end
def build_resource
- resource = resource_base.new(@params[name] || {})
+ params = @options[:class] \
+ ? @params[@options[:class].to_s.underscore.gsub('/', '_')] \
+ : @params[name] || {}
+ resource = resource_base.new(params)
resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
initial_attributes.each do |attr_name, value|
resource.send("#{attr_name}=", value)
View
@@ -111,7 +111,7 @@ def matches_conditions_hash?(subject, conditions = @conditions)
else
!attribute.nil? && matches_conditions_hash?(attribute, value)
end
- elsif value.kind_of?(Array) || value.kind_of?(Range)
+ elsif value.kind_of?(Enumerable)
value.include? attribute
else
attribute == value
@@ -123,7 +123,7 @@ def matches_conditions_hash?(subject, conditions = @conditions)
end
def nested_subject_matches_conditions?(subject_hash)
- parent, child = subject_hash.shift
+ parent, child = subject_hash.first
matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
end
@@ -249,7 +249,15 @@
@ability.can?(:read, 1..5).should be_true
@ability.can?(:read, 4..6).should be_false
end
-
+
+ it "should accept a set as a condition value" do
+ mock(object_with_foo_2 = Object.new).foo { 2 }
+ mock(object_with_foo_3 = Object.new).foo { 3 }
+ @ability.can :read, Object, :foo => [1, 2, 5].to_set
+ @ability.can?(:read, object_with_foo_2).should be_true
+ @ability.can?(:read, object_with_foo_3).should be_false
+ end
+
it "should not match subjects return nil for methods that must match nested a nested conditions hash" do
mock(object_with_foo = Object.new).foo { :bar }
@ability.can :read, Array, :first => { :foo => :bar }
@@ -298,6 +306,14 @@ class A; include B; end
@ability.can?(:read, 123 => Range).should be_true
end
+ it "passing a hash of subjects with multiple definitions should check permissions correctly" do
+ @ability.can :read, Range, :string => {:length => 4}
+ @ability.can [:create, :read], Range, :string => {:upcase => 'FOO'}
+ @ability.can?(:read, "foo" => Range).should be_true
+ @ability.can?(:read, "foobar" => Range).should be_false
+ @ability.can?(:read, 1234 => Range).should be_true
+ end
+
it "should allow to check ability on Hash-like object" do
class Container < Hash; end
@ability.can :read, Container
@@ -49,14 +49,14 @@
it "authorize_resource should setup a before filter which passes call to ControllerResource" do
stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.authorize_resource
- mock(@controller_class).before_filter(:except => :show) { |options, block| block.call(@controller) }
- @controller_class.authorize_resource :foo => :bar, :except => :show
+ mock(@controller_class).before_filter(:except => :show, :if => true) { |options, block| block.call(@controller) }
+ @controller_class.authorize_resource :foo => :bar, :except => :show, :if => true
end
it "load_resource should setup a before filter which passes call to ControllerResource" do
stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.load_resource
- mock(@controller_class).before_filter(:only => [:show, :index]) { |options, block| block.call(@controller) }
- @controller_class.load_resource :foo => :bar, :only => [:show, :index]
+ mock(@controller_class).before_filter(:only => [:show, :index], :unless => false) { |options, block| block.call(@controller) }
+ @controller_class.load_resource :foo => :bar, :only => [:show, :index], :unless => false
end
it "skip_authorization_check should set up a before filter which sets @_authorized to true" do
@@ -62,6 +62,14 @@ class Project < ::Project; end
@controller.instance_variable_get(:@project).name.should == "foobar"
end
+ it "should build a new resource for namespaced model with hash if params[:id] is not specified" do
+ project = Sub::Project.create!
+ @params.merge!(:action => "create", 'sub_project' => {:name => "foobar"})
+ resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project)
+ resource.load_resource
+ @controller.instance_variable_get(:@project).name.should == "foobar"
+ end
+
it "should build a new resource with attributes from current ability" do
@params.merge!(:action => "new")
@ability.can(:create, Project, :name => "from conditions")
@@ -340,6 +348,14 @@ class Project < ::Project; end
@controller.instance_variable_get(:@project).should == project
end
+ it "should load the model using a custom namespaced class" do
+ project = Sub::Project.create!
+ @params.merge!(:action => "show", :id => project.id)
+ resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project)
+ resource.load_resource
+ @controller.instance_variable_get(:@project).should == project
+ end
+
it "should authorize based on resource name if class is false" do
@params.merge!(:action => "show", :id => 123)
stub(@controller).authorize!(:show, :project) { raise CanCan::AccessDenied }
@@ -355,15 +371,15 @@ class Project < ::Project; end
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
@controller.instance_variable_get(:@custom_project).should == project
end
-
+
it "should load resource using custom ID param" do
project = Project.create!
@params.merge!(:action => "show", :the_project => project.id)
resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project)
resource.load_resource
@controller.instance_variable_get(:@project).should == project
end
-
+
it "should load resource using custom find_by attribute" do
project = Project.create!(:name => "foo")
@params.merge!(:action => "show", :id => "foo")
View
@@ -31,6 +31,21 @@ class Category < SuperModel::Base
has_many :projects
end
+module Sub
+ class Project < SuperModel::Base
+ belongs_to :category
+ attr_accessor :category # why doesn't SuperModel do this automatically?
+
+ def self.respond_to?(method, include_private = false)
+ if method.to_s == "find_by_name!" # hack to simulate ActiveRecord
+ true
+ else
+ super
+ end
+ end
+ end
+end
+
class Project < SuperModel::Base
belongs_to :category
attr_accessor :category # why doesn't SuperModel do this automatically?

0 comments on commit 1141dab

Please sign in to comment.