From 605063b974d4e10c601585bb178e9aba7b6092c5 Mon Sep 17 00:00:00 2001
From: Logan Raarup <logan@logan.dk>
Date: Tue, 11 May 2010 19:30:28 +0800
Subject: [PATCH] Make sure conditions on associations are pluralized

---
 lib/cancan/ability.rb                       |  4 ++--
 lib/cancan/active_record_additions.rb       |  2 +-
 lib/cancan/can_definition.rb                | 16 +++++++++++++++-
 spec/cancan/active_record_additions_spec.rb |  4 ++--
 spec/cancan/can_definition_spec.rb          |  6 ++++++
 5 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/lib/cancan/ability.rb b/lib/cancan/ability.rb
index 535663e..b20c0f1 100644
--- a/lib/cancan/ability.rb
+++ b/lib/cancan/ability.rb
@@ -190,11 +190,11 @@ module CanCan
     # If the ability is not defined then false is returned so be sure to take that into consideration.
     # If the ability is defined using a block then this will raise an exception since a hash of conditions cannot be
     # determined from that.
-    def conditions(action, subject)
+    def conditions(action, subject, options = {})
       can_definition = matching_can_definition(action, subject)
       if can_definition
         raise Error, "Cannot determine ability conditions from block for #{action.inspect} #{subject.inspect}" if can_definition.block
-        can_definition.conditions || {}
+        can_definition.conditions(options) || {}
       else
         false
       end
diff --git a/lib/cancan/active_record_additions.rb b/lib/cancan/active_record_additions.rb
index 2afa33d..e5bda3b 100644
--- a/lib/cancan/active_record_additions.rb
+++ b/lib/cancan/active_record_additions.rb
@@ -20,7 +20,7 @@ module CanCan
       # Here only the articles which the user can update are returned. This
       # internally uses Ability#conditions method, see that for more information.
       def accessible_by(ability, action = :read)
-        conditions = ability.conditions(action, self) || {:id => nil}
+        conditions = ability.conditions(action, self, :tableize => true) || {:id => nil}
         joins = ability.association_joins(action, self)
         if respond_to? :where
           where(conditions).joins(joins)
diff --git a/lib/cancan/can_definition.rb b/lib/cancan/can_definition.rb
index 9b3b945..c1dce1e 100644
--- a/lib/cancan/can_definition.rb
+++ b/lib/cancan/can_definition.rb
@@ -1,7 +1,8 @@
 module CanCan
   # This class is used internally and should only be called through Ability.
   class CanDefinition # :nodoc:
-    attr_reader :conditions, :block
+    include ActiveSupport::Inflector
+    attr_reader :block
     
     def initialize(base_behavior, action, subject, conditions, block)
       @base_behavior = base_behavior
@@ -25,6 +26,19 @@ module CanCan
       result = can_without_base_behavior?(action, subject, extra_args)
       @base_behavior ? result : !result
     end
+    
+    def conditions(options = {})
+      if options[:tableize] and @conditions.kind_of? Hash
+        @conditions.inject({}) do |tableized_conditions, (name, value)|
+          name = tableize(name).to_sym if value.kind_of? Hash
+          
+          tableized_conditions[name] = value
+          tableized_conditions
+        end
+      else
+        @conditions
+      end
+    end
 
     def association_joins(conditions = @conditions)
       joins = []
diff --git a/spec/cancan/active_record_additions_spec.rb b/spec/cancan/active_record_additions_spec.rb
index 640f44a..41aaf3c 100644
--- a/spec/cancan/active_record_additions_spec.rb
+++ b/spec/cancan/active_record_additions_spec.rb
@@ -16,13 +16,13 @@ describe CanCan::ActiveRecordAdditions do
   
   it "should call where with matching ability conditions" do
     @ability.can :read, @model_class, :foo => {:bar => 1}
-    stub(@model_class).where(:foo => { :bar => 1 }).stub!.joins([:foo]) { :found_records }
+    stub(@model_class).where(:foos => { :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 => {:bar => 1}
-    stub(@model_class).scoped(:conditions => {:foo => {:bar => 1}}, :joins => [:foo]) { :found_records }
+    stub(@model_class).scoped(:conditions => {:foos => {:bar => 1}}, :joins => [:foo]) { :found_records }
     @model_class.accessible_by(@ability).should == :found_records
   end
 end
diff --git a/spec/cancan/can_definition_spec.rb b/spec/cancan/can_definition_spec.rb
index 697dc74..c9f7633 100644
--- a/spec/cancan/can_definition_spec.rb
+++ b/spec/cancan/can_definition_spec.rb
@@ -30,4 +30,10 @@ describe CanCan::CanDefinition do
     @conditions[:foo] = {:bar => {1 => 2}}
     @can.association_joins.should == [{:foo => [:bar]}]
   end
+  
+  it "should return table names in conditions for association joins" do
+    @conditions[:foo] = {:bar => 1}
+    @conditions[:test] = 1
+    @can.conditions(:tableize => true).should == { :foos => { :bar => 1}, :test => 1 }
+  end
 end