adding joins clause to accessible_by when conditions are across associations
This commit is contained in:
parent
4da31c0709
commit
e20081454f
|
@ -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
|
||||
|
|
|
@ -200,6 +200,16 @@ module CanCan
|
|||
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
|
||||
|
|
|
@ -21,10 +21,11 @@ module CanCan
|
|||
# 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
|
||||
|
|
|
@ -26,6 +26,21 @@ module CanCan
|
|||
@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
|
||||
|
||||
def matches_action?(action)
|
||||
|
|
|
@ -10,19 +10,19 @@ describe CanCan::ActiveRecordAdditions do
|
|||
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
|
||||
|
|
33
spec/cancan/can_definition_spec.rb
Normal file
33
spec/cancan/can_definition_spec.rb
Normal file
|
@ -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
|
Loading…
Reference in New Issue
Block a user