Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Allow multiple abilities with associations

There are two issues with the current way cancan handles associations:

1) Records are returned multiple times in some circumstances
2) Several defined abilities prevent some records to show up under certain circumstances

This commit includes tests for both cases. It fixes both problems by changing `joins` to `includes` for the AR adapters. This could have performance implications, since `includes` will also select all columns in the associated records. We tried various ways of achieving the same thing using Arel directly, but were unable to make this work due to lack of support for outer joins in Rails 3.1.

This closes issues #724, #566 and #613
  • Loading branch information...
commit 2ffdf46be1f5c2d7b48caa12800e7b7934cae9e6 1 parent b4285ae
Jonas Nicklas and Nicklas Ramhöj authored
View
4 lib/cancan/model_adapters/active_record_adapter.rb
@@ -91,9 +91,9 @@ def database_records
elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
mergeable_conditions = @rules.select {|rule| rule.unmergeable? }.blank?
if mergeable_conditions
- @model_class.where(conditions).joins(joins)
+ @model_class.where(conditions).includes(joins)
else
- @model_class.where(*(@rules.map(&:conditions))).joins(joins)
+ @model_class.where(*(@rules.map(&:conditions))).includes(joins)
end
else
@model_class.scoped(:conditions => conditions, :joins => joins)
View
18 spec/cancan/model_adapters/active_record_adapter_spec.rb
@@ -102,6 +102,24 @@
Comment.accessible_by(@ability).should == [comment1]
end
+ it "should only read articles which are published or in visible categories" do
+ @ability.can :read, Article, :category => { :visible => true }
+ @ability.can :read, Article, :published => true
+ article1 = Article.create!(:published => true)
+ article2 = Article.create!(:published => false)
+ article3 = Article.create!(:published => false, :category => Category.create!(:visible => true))
+ Article.accessible_by(@ability).should == [article1, article3]
+ end
+
+ it "should only read categories once even if they have multiple articles" do
+ @ability.can :read, Category, :articles => { :published => true }
+ @ability.can :read, Article, :published => true
+ category = Category.create!
+ Article.create!(:published => true, :category => category)
+ Article.create!(:published => true, :category => category)
+ Category.accessible_by(@ability).should == [category]
+ end
+
it "should only read comments for visible categories through articles" do
@ability.can :read, Comment, :article => { :category => { :visible => true } }
comment1 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => true)))
Please sign in to comment.
Something went wrong with that request. Please try again.