Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

adding joins clause to accessible_by when conditions are across assoc…

…iations
  • Loading branch information...
commit e20081454f49ad8b79fc43049b6e773901748247 1 parent 4da31c0
@ryanb authored
View
2  CHANGELOG.rdoc
@@ -1,3 +1,5 @@
+* Adding joins clause to accessible_by when conditions are across associations
+
1.1.1 (April 17, 2010)
* Fixing behavior in Rails 3 by properly initializing ResourceAuthorization
View
10 lib/cancan/ability.rb
@@ -200,6 +200,16 @@ def conditions(action, subject)
end
end
+ # Returns the associations used in conditions. This is usually used in the :joins option for a search.
+ # See ActiveRecordAdditions#accessible_by for use in Active Record.
+ def association_joins(action, subject)
+ can_definition = matching_can_definition(action, subject)
+ if can_definition
+ raise Error, "Cannot determine association joins from block for #{action.inspect} #{subject.inspect}" if can_definition.block
+ can_definition.association_joins
+ end
+ end
+
private
def can_definitions
View
5 lib/cancan/active_record_additions.rb
@@ -21,10 +21,11 @@ module ClassMethods
# internally uses Ability#conditions method, see that for more information.
def accessible_by(ability, action = :read)
conditions = ability.conditions(action, self) || {:id => nil}
+ joins = ability.association_joins(action, self)
if respond_to? :where
- where(conditions)
+ where(conditions).joins(joins)
else
- scoped(:conditions => conditions)
+ scoped(:conditions => conditions, :joins => joins)
end
end
end
View
15 lib/cancan/can_definition.rb
@@ -25,6 +25,21 @@ def can?(action, subject, extra_args)
result = can_without_base_behavior?(action, subject, extra_args)
@base_behavior ? result : !result
end
+
+ def association_joins(conditions = @conditions)
+ joins = []
+ conditions.each do |name, value|
+ if value.kind_of? Hash
+ nested = association_joins(value)
+ if nested
+ joins << {name => nested}
+ else
+ joins << name
+ end
+ end
+ end
+ joins unless joins.empty?
+ end
private
View
10 spec/cancan/active_record_additions_spec.rb
@@ -10,19 +10,19 @@
end
it "should call where(:id => nil) when no ability is defined so no records are found" do
- stub(@model_class).where(:id => nil) { :no_where }
+ stub(@model_class).where(:id => nil).stub!.joins(nil) { :no_where }
@model_class.accessible_by(@ability, :read).should == :no_where
end
it "should call where with matching ability conditions" do
- @ability.can :read, @model_class, :foo => 1
- stub(@model_class).where(:foo => 1) { :found_records }
+ @ability.can :read, @model_class, :foo => {:bar => 1}
+ stub(@model_class).where(:foo => { :bar => 1 }).stub!.joins([:foo]) { :found_records }
@model_class.accessible_by(@ability, :read).should == :found_records
end
it "should default to :read ability and use scoped when where isn't available" do
- @ability.can :read, @model_class, :foo => 1
- stub(@model_class).scoped(:conditions => {:foo => 1}) { :found_records }
+ @ability.can :read, @model_class, :foo => {:bar => 1}
+ stub(@model_class).scoped(:conditions => {:foo => {:bar => 1}}, :joins => [:foo]) { :found_records }
@model_class.accessible_by(@ability).should == :found_records
end
end
View
33 spec/cancan/can_definition_spec.rb
@@ -0,0 +1,33 @@
+require "spec_helper"
+
+describe CanCan::CanDefinition do
+ before(:each) do
+ @conditions = {}
+ @can = CanCan::CanDefinition.new(true, :read, Integer, @conditions, nil)
+ end
+
+ it "should return no association joins if none exist" do
+ @can.association_joins.should be_nil
+ end
+
+ it "should return no association for joins if just attributes" do
+ @conditions[:foo] = :bar
+ @can.association_joins.should be_nil
+ end
+
+ it "should return single association for joins" do
+ @conditions[:foo] = {:bar => 1}
+ @can.association_joins.should == [:foo]
+ end
+
+ it "should return multiple associations for joins" do
+ @conditions[:foo] = {:bar => 1}
+ @conditions[:test] = {1 => 2}
+ @can.association_joins.map(&:to_s).sort.should == [:foo, :test].map(&:to_s).sort
+ end
+
+ it "should return nested associations for joins" do
+ @conditions[:foo] = {:bar => {1 => 2}}
+ @can.association_joins.should == [{:foo => [:bar]}]
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.